@transcend-io/sdk 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +4 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PURPOSES","PAGE_SIZE","PURPOSES","PAGE_SIZE","pmap","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","MAX_PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","MAX_PAGE_SIZE","MAX_PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","CHUNK_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","CHUNK_SIZE"],"sources":["../src/gqls/shared.ts","../src/api/buildTranscendGraphQLClient.ts","../src/api/makeGraphQLRequest.ts","../src/api/gqls/organization.ts","../src/api/createSombraGotInstance.ts","../src/data-inventory/gqls/businessEntity.ts","../src/data-inventory/fetchAllBusinessEntities.ts","../src/data-inventory/gqls/dataCategory.ts","../src/data-inventory/fetchAllDataCategories.ts","../src/data-inventory/gqls/dataPoint.ts","../src/data-inventory/fetchAllDataPoints.ts","../src/data-inventory/gqls/dataSilo.ts","../src/data-inventory/fetchAllDataSilos.ts","../src/data-inventory/gqls/identifier.ts","../src/data-inventory/fetchAllIdentifiers.ts","../src/data-inventory/gqls/processingActivity.ts","../src/data-inventory/fetchAllProcessingActivities.ts","../src/data-inventory/gqls/vendor.ts","../src/data-inventory/fetchAllVendors.ts","../src/data-inventory/fetchEnrichedDataSilos.ts","../src/data-inventory/syncBusinessEntities.ts","../src/data-inventory/syncDataCategories.ts","../src/data-inventory/syncDataSiloDependencies.ts","../src/data-inventory/syncProcessingActivities.ts","../src/data-inventory/syncVendors.ts","../src/preference-management/gqls/purpose.ts","../src/preference-management/fetchAllPurposes.ts","../src/preference-management/gqls/preferenceTopic.ts","../src/preference-management/fetchAllPreferenceTopics.ts","../src/preference-management/fetchAllPurposesAndPreferences.ts","../src/preference-management/gqls/preferenceAccessTokens.ts","../src/preference-management/createPreferenceAccessTokens.ts","../src/preference-management/types.ts","../src/preference-management/codecs.ts","../src/preference-management/getPreferenceMetadataFromRow.ts","../src/preference-management/getPreferenceIdentifiersFromRow.ts","../src/preference-management/getUniquePreferenceIdentifierNamesFromRow.ts","../src/preference-management/getPreferenceUpdatesFromRow.ts","../src/preference-management/checkIfPendingPreferenceUpdatesAreNoOp.ts","../src/preference-management/checkIfPendingPreferenceUpdatesCauseConflict.ts","../src/preference-management/withPreferenceRetry.ts","../src/preference-management/transformPreferenceRecordToCsv.ts","../src/preference-management/buildConsentChunks.ts","../src/preference-management/pickConsentChunkMode.ts","../src/preference-management/getComparisonTimeForRecord.ts","../src/preference-management/iterateConsentPages.ts","../src/preference-management/consentWindowHasAny.ts","../src/preference-management/discoverConsentWindow.ts","../src/preference-management/fetchConsentPreferences.ts","../src/preference-management/getPreferencesForIdentifiers.ts","../src/preference-management/fetchConsentPreferencesChunked.ts","../src/preference-management/loadReferenceData.ts","../src/administration/gqls/attribute.ts","../src/administration/fetchAllAttributes.ts","../src/administration/gqls/message.ts","../src/administration/fetchAllMessages.ts","../src/administration/gqls/team.ts","../src/administration/fetchAllTeams.ts","../src/administration/gqls/user.ts","../src/administration/fetchAllUsers.ts","../src/administration/gqls/apiKey.ts","../src/administration/fetchApiKeys.ts","../src/administration/formatRegions.ts","../src/administration/gqls/auth.ts","../src/administration/loginUser.ts","../src/administration/manageApiKeys.ts","../src/administration/setResourceAttributes.ts","../src/administration/syncAttribute.ts","../src/administration/syncIntlMessages.ts","../src/administration/syncTeams.ts","../src/administration/gqls/attributeKey.ts","../src/consent/createTranscendConsentGotInstance.ts","../src/consent/gqls/consentManager.ts","../src/consent/deployConsentManager.ts","../src/consent/gqls/consentManagerMetrics.ts","../src/consent/gqls/experiences.ts","../src/consent/fetchConsentManagerId.ts","../src/consent/gqls/shared.ts","../src/consent/gqls/cookies.ts","../src/consent/fetchAllCookies.ts","../src/consent/gqls/dataFlows.ts","../src/consent/fetchAllDataFlows.ts","../src/consent/gqls/privacyCenter.ts","../src/consent/fetchPrivacyCenterId.ts","../src/consent/gqls/policy.ts","../src/consent/fetchAllPolicies.ts","../src/consent/fetchAllPrivacyCenters.ts","../src/consent/gqls/processingPurpose.ts","../src/consent/fetchAllProcessingPurposes.ts","../src/consent/gqls/purposes.ts","../src/consent/gqls/partitions.ts","../src/consent/gqls/stats.ts","../src/consent/syncPartitions.ts","../src/consent/syncConsentManager.ts","../src/consent/syncCookies.ts","../src/consent/syncDataFlows.ts","../src/consent/syncPolicies.ts","../src/consent/syncPrivacyCenter.ts","../src/consent/syncProcessingPurposes.ts","../src/dsr-automation/gqls/requestEnricher.ts","../src/dsr-automation/fetchAllRequestEnrichers.ts","../src/dsr-automation/gqls/sombraVersion.ts","../src/dsr-automation/fetchAllRequestIdentifiers.ts","../src/dsr-automation/gqls/requestIdentifier.ts","../src/dsr-automation/fetchAllRequestIdentifierMetadata.ts","../src/dsr-automation/gqls/dataSubject.ts","../src/dsr-automation/fetchDataSubjects.ts","../src/dsr-automation/gqls/dsrIdentifier.ts","../src/dsr-automation/fetchIdentifiers.ts","../src/dsr-automation/retryRequestEnricher.ts","../src/dsr-automation/syncDataSubject.ts","../src/dsr-automation/gqls/enricher.ts","../src/dsr-automation/syncEnrichers.ts","../src/dsr-automation/syncIdentifier.ts","../src/dsr-automation/gqls/siloDiscovery.ts","../src/dsr-automation/fetchActiveSiloDiscoPlugin.ts","../src/dsr-automation/gqls/action.ts","../src/dsr-automation/fetchAllActions.ts","../src/dsr-automation/fetchAllAttributeKeys.ts","../src/dsr-automation/gqls/siloDiscoveryResult.ts","../src/dsr-automation/fetchAllSiloDiscoveryResults.ts","../src/dsr-automation/gqls/catalog.ts","../src/dsr-automation/fetchCatalogs.ts","../src/dsr-automation/gqls/requestDataSilo.ts","../src/dsr-automation/fetchRequestDataSilo.ts","../src/dsr-automation/gqls/requestFile.ts","../src/dsr-automation/fetchRequestFilesForRequest.ts","../src/dsr-automation/formatAttributeValues.ts","../src/dsr-automation/syncAction.ts","../src/dsr-automation/gqls/template.ts","../src/dsr-automation/syncTemplates.ts","../src/dsr-automation/uploadSiloDiscoveryResults.ts","../src/ai/gqls/promptRun.ts","../src/ai/addMessagesToPromptRun.ts","../src/ai/gqls/agentFile.ts","../src/ai/fetchAllAgentFiles.ts","../src/ai/gqls/agentFunction.ts","../src/ai/fetchAllAgentFunctions.ts","../src/ai/gqls/agent.ts","../src/ai/fetchAllAgents.ts","../src/ai/gqls/largeLanguageModel.ts","../src/ai/fetchLargeLanguageModels.ts","../src/ai/gqls/prompt.ts","../src/ai/fetchPromptGroups.ts","../src/ai/fetchPromptPartials.ts","../src/ai/fetchPrompts.ts","../src/ai/gqls/promptThread.ts","../src/ai/fetchPromptThreads.ts","../src/ai/reportPromptRun.ts","../src/ai/syncAgentFiles.ts","../src/ai/syncAgentFunctions.ts","../src/ai/syncAgents.ts","../src/ai/syncPromptGroups.ts","../src/ai/syncPromptPartials.ts","../src/ai/syncPrompts.ts","../src/assessments/gqls/actionItemCollection.ts","../src/assessments/fetchAllActionItemCollections.ts","../src/assessments/gqls/actionItem.ts","../src/assessments/fetchAllActionItems.ts","../src/assessments/gqls/assessment.ts","../src/assessments/fetchAllAssessments.ts","../src/assessments/parseAssessmentDisplayLogic.ts","../src/assessments/parseAssessmentRiskLogic.ts","../src/assessments/syncActionItemCollections.ts","../src/assessments/syncActionItems.ts","../src/code-intelligence/gqls/codePackage.ts","../src/code-intelligence/fetchAllCodePackages.ts","../src/code-intelligence/gqls/repository.ts","../src/code-intelligence/fetchAllRepositories.ts","../src/code-intelligence/gqls/softwareDevelopmentKit.ts","../src/code-intelligence/fetchAllSoftwareDevelopmentKits.ts","../src/code-intelligence/syncRepositories.ts","../src/code-intelligence/syncSoftwareDevelopmentKits.ts","../src/index.ts"],"sourcesContent":["/**\n * Shared GQL field selection constants and types used across\n * multiple SDK domains (consent, data-inventory, etc.).\n */\n\n/** Owner fields shared across queries */\nexport const OWNER_FIELDS = `\n id\n name\n email\n`;\n\n/** Team fields shared across queries */\nexport const TEAM_FIELDS = `\n id\n name\n`;\n\n/** Attribute value fields (with nested key) shared across queries */\nexport const ATTRIBUTE_VALUE_FIELDS = `\n id\n name\n attributeKey {\n id\n name\n }\n`;\n\n/** Owner assigned to an entity */\nexport interface TranscendOwnerGql {\n /** Owner ID */\n id: string;\n /** Owner display name */\n name: string;\n /** Owner email */\n email: string;\n}\n\n/** Team assigned to an entity */\nexport interface TranscendTeamGql {\n /** Team ID */\n id: string;\n /** Team name */\n name: string;\n}\n\n/** Attribute value on an entity */\nexport interface TranscendAttributeValueGql {\n /** Attribute value ID */\n id: string;\n /** Attribute value name */\n name: string;\n /** Attribute key */\n attributeKey: {\n /** Attribute key ID */\n id: string;\n /** Attribute key name */\n name: string;\n };\n}\n","import { GraphQLClient } from 'graphql-request';\n\n/**\n * Create a GraphQL client\n *\n * @param transcendUrl - Transcend API URL\n * @param headers - Request headers to include in each request\n * @param version - Optional version string to include in request headers\n * @returns GraphQL client\n */\nexport function buildTranscendGraphQLClientGeneric(\n transcendUrl: string,\n headers: Record<string, string>,\n version?: string,\n): GraphQLClient {\n return new GraphQLClient(`${transcendUrl}/graphql`, {\n headers: {\n ...headers,\n ...(version ? { version } : {}),\n },\n });\n}\n\n/**\n * Create a GraphQL client capable of submitting requests with an API key\n *\n * @param transcendUrl - Transcend API URL\n * @param auth - API key to authenticate to API\n * @param version - Optional version string to include in request headers\n * @returns GraphQL client\n */\nexport function buildTranscendGraphQLClient(\n transcendUrl: string,\n auth: string,\n version?: string,\n): GraphQLClient {\n return buildTranscendGraphQLClientGeneric(\n transcendUrl,\n { Authorization: `Bearer ${auth}` },\n version,\n );\n}\n","import { sleepPromise, type Logger } from '@transcend-io/utils';\nimport type { GraphQLClient, RequestDocument, Variables } from 'graphql-request';\n\n/** Logger that silently discards all messages */\nexport const NOOP_LOGGER: Logger = {\n info: () => {},\n warn: () => {},\n error: () => {},\n debug: () => {},\n};\n\nconst DEFAULT_MAX_RETRIES = 4;\n\nconst KNOWN_ERRORS = [\n 'syntax error',\n 'got invalid value',\n 'Client error',\n 'cannot affect row a second time',\n 'GRAPHQL_VALIDATION_FAILED',\n];\n\n/**\n * Make a GraphQL request with retries\n *\n * @param client - GraphQL client\n * @param document - GraphQL document\n * @param options - Options including logger, variables, headers, and retry config\n * @returns Response\n */\nexport async function makeGraphQLRequest<T, V extends Variables = Variables>(\n client: GraphQLClient,\n document: RequestDocument,\n options: {\n /** GraphQL variables */\n variables?: V;\n /** Logger for retry/error messages */\n logger?: Logger;\n /** Additional request headers */\n requestHeaders?: Record<string, string> | string[][] | Headers;\n /** Max number of retry attempts (default 4) */\n maxRetries?: number;\n },\n): Promise<T> {\n const {\n variables,\n logger = NOOP_LOGGER,\n requestHeaders,\n maxRetries = DEFAULT_MAX_RETRIES,\n } = options;\n\n let retryCount = 0;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n try {\n const result = await client.request(document, variables, requestHeaders);\n return result as T;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (err: any) {\n if (err.message?.includes('API key is invalid')) {\n throw new Error(\n 'API key is invalid. ' +\n 'Please ensure that the key provided has the proper scope and is not expired, ' +\n 'and that the transcendUrl corresponds to the correct backend for your organization.',\n );\n }\n\n if (KNOWN_ERRORS.some((msg) => err.message?.includes(msg))) {\n throw err;\n }\n\n if (err.message?.startsWith('Client error: Too many requests')) {\n const rateLimitResetAt = err.response?.headers?.get('x-ratelimit-reset');\n const sleepTime = rateLimitResetAt\n ? new Date(rateLimitResetAt).getTime() - new Date().getTime() + 100\n : 1000 * 10;\n logger.warn(`DETECTED RATE LIMIT: ${err.message}. Sleeping for ${sleepTime}ms`);\n await sleepPromise(sleepTime);\n }\n\n if (retryCount >= maxRetries) {\n throw err;\n }\n retryCount += 1;\n logger.warn(`Retrying failed request (${retryCount} / ${maxRetries}): ${err.message}`);\n }\n }\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const ORGANIZATION: DocumentNode = parse(gql`\n query TranscendCliOrganization {\n organization {\n sombra {\n customerUrl\n }\n }\n }\n`);\n","import type { Logger } from '@transcend-io/utils';\nimport got, { type Got } from 'got';\n\nimport { buildTranscendGraphQLClient } from './buildTranscendGraphQLClient.js';\nimport { ORGANIZATION } from './gqls/organization.js';\nimport { makeGraphQLRequest, NOOP_LOGGER } from './makeGraphQLRequest.js';\n\n/**\n * Instantiate an instance of got that is capable of making requests\n * to a sombra gateway.\n *\n * @param transcendUrl - URL of Transcend API\n * @param transcendApiKey - Transcend API key\n * @param options - Additional options\n * @returns The instance of got that is capable of making requests to the customer ingress\n */\nexport async function createSombraGotInstance(\n transcendUrl: string,\n transcendApiKey: string,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Sombra API key */\n sombraApiKey?: string;\n /** Override Sombra URL (replaces process.env.SOMBRA_URL lookup) */\n sombraUrl?: string;\n } = {},\n): Promise<Got> {\n const { logger = NOOP_LOGGER, sombraApiKey, sombraUrl } = options;\n\n const client = buildTranscendGraphQLClient(transcendUrl, transcendApiKey);\n const { organization } = await makeGraphQLRequest<{\n /** Organization */\n organization: {\n /** Primary Sombra */\n sombra: {\n /** URL */\n customerUrl: string;\n };\n };\n }>(client, ORGANIZATION, { logger });\n\n const { customerUrl } = organization.sombra;\n const sombraToUse = sombraUrl || customerUrl;\n\n if (\n !sombraUrl &&\n [\n 'https://sombra-reverse-tunnel.transcend.io',\n 'https://sombra-reverse-tunnel.us.transcend.io',\n ].includes(customerUrl)\n ) {\n throw new Error(\n 'It looks like your Sombra customer ingress URL has not been set up. ' +\n 'Please follow the instructions here to configure networking for Sombra: ' +\n 'https://docs.transcend.io/docs/articles/sombra/deploying/customizing-sombra/networking',\n );\n }\n logger.info(`Using sombra: ${sombraToUse}`);\n\n return (got as unknown as Got).extend({\n prefixUrl: sombraToUse,\n headers: {\n Authorization: `Bearer ${transcendApiKey}`,\n ...(sombraApiKey ? { 'X-Sombra-Authorization': `Bearer ${sombraApiKey}` } : {}),\n },\n });\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const BUSINESS_ENTITIES = gql`\n query TranscendCliBusinessEntities($first: Int!, $offset: Int!) {\n businessEntities(\n first: $first\n offset: $offset\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n useMaster: false\n ) {\n nodes {\n id\n title\n description\n dataProtectionOfficerName\n dataProtectionOfficerEmail\n address\n headquarterCountry\n headquarterSubDivision\n attributeValues {\n name\n attributeKey {\n name\n }\n }\n }\n }\n }\n`;\n\nexport const CREATE_BUSINESS_ENTITY = gql`\n mutation TranscendCliCreateBusinessEntity($input: CreateBusinessEntityInput!) {\n createBusinessEntity(input: $input) {\n businessEntity {\n id\n title\n description\n dataProtectionOfficerName\n dataProtectionOfficerEmail\n address\n headquarterCountry\n headquarterSubDivision\n attributeValues {\n name\n attributeKey {\n name\n }\n }\n }\n }\n }\n`;\n\nexport const UPDATE_BUSINESS_ENTITIES = gql`\n mutation TranscendCliUpdateBusinessEntities($input: [UpdateBusinessEntityInput!]!) {\n updateBusinessEntities(input: { businessEntities: $input }) {\n clientMutationId\n }\n }\n`;\n","import { IsoCountryCode, IsoCountrySubdivisionCode } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { BUSINESS_ENTITIES } from './gqls/businessEntity.js';\n\nexport interface BusinessEntity {\n /** ID of business entity */\n id: string;\n /** Title of business entity */\n title: string;\n /** Description of business entity */\n description?: string;\n /** Data protection officer name */\n dataProtectionOfficerName?: string;\n /** Data protection officer email */\n dataProtectionOfficerEmail?: string;\n /** Address of business entity */\n address?: string;\n /** Headquarters of business entity */\n headquarterCountry?: IsoCountryCode;\n /** Subdivision of business entity */\n headquarterSubDivision?: IsoCountrySubdivisionCode;\n /** Attributes */\n attributeValues: {\n /** Name of attribute value */\n name: string;\n /** Attribute key */\n attributeKey: {\n /** Name of attribute key */\n name: string;\n };\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all businessEntities in the organization\n *\n * @param client - GraphQL client\n * @returns All businessEntities in the organization\n */\nexport async function fetchAllBusinessEntities(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<BusinessEntity[]> {\n const { logger } = options;\n const businessEntities: BusinessEntity[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n businessEntities: { nodes },\n } = await makeGraphQLRequest<{\n /** Business entities */\n businessEntities: {\n /** List */\n nodes: BusinessEntity[];\n };\n }>(client, BUSINESS_ENTITIES, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n businessEntities.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return businessEntities.sort((a, b) => a.title.localeCompare(b.title));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// orderBy: [\n// { field: createdAt, direction: ASC }\n// { field: name, direction: ASC }\n// ]\nexport const DATA_SUB_CATEGORIES = gql`\n query TranscendCliDataSubCategories($first: Int!, $offset: Int!) {\n dataSubCategories(first: $first, offset: $offset, isExportCsv: true, useMaster: false) {\n nodes {\n id\n name\n category\n description\n regex\n teams {\n name\n }\n owners {\n email\n }\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n }\n }\n }\n`;\n\nexport const CREATE_DATA_SUB_CATEGORY = gql`\n mutation TranscendCliCreateDataSubCategory($input: CreateDataInventorySubCategoryInput!) {\n createDataSubCategory(input: $input) {\n dataSubCategory {\n id\n name\n category\n }\n }\n }\n`;\n\nexport const UPDATE_DATA_SUB_CATEGORIES = gql`\n mutation TranscendCliUpdateDataSubCategories($input: UpdateDataSubCategoriesInput!) {\n updateDataSubCategories(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { DataCategoryType } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { DATA_SUB_CATEGORIES } from './gqls/dataCategory.js';\n\nexport interface DataSubCategory {\n /** ID of data category */\n id: string;\n /** Name of data category */\n name: string;\n /** Type of data category */\n category: DataCategoryType;\n /** Description of data category */\n description?: string;\n /** Regex for data category */\n regex?: string;\n /** Assigned teams */\n teams: {\n /** Team name */\n name: string;\n }[];\n /** Assigned owners */\n owners: {\n /** Email */\n email: string;\n }[];\n /** Custom fields */\n attributeValues: {\n /** Name of attribute value */\n name: string;\n /** Attribute key that the value represents */\n attributeKey: {\n /** Name of attribute team */\n name: string;\n };\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all dataSubCategories in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All dataSubCategories in the organization\n */\nexport async function fetchAllDataCategories(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<DataSubCategory[]> {\n const { logger } = options;\n const dataSubCategories: DataSubCategory[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n dataSubCategories: { nodes },\n } = await makeGraphQLRequest<{\n /** DataCategories */\n dataSubCategories: {\n /** List */\n nodes: DataSubCategory[];\n };\n }>(client, DATA_SUB_CATEGORIES, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n dataSubCategories.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return dataSubCategories.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_POINTS = gql`\n query TranscendCliDataPoints($filterBy: DataPointFiltersInput, $first: Int!, $offset: Int!) {\n dataPoints(\n filterBy: $filterBy\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n title {\n defaultMessage\n }\n description {\n defaultMessage\n }\n owners {\n email\n }\n teams {\n name\n }\n name\n path\n actionSettings {\n type\n active\n }\n dataCollection {\n title {\n defaultMessage\n }\n }\n dbIntegrationQueries {\n query\n suggestedQuery\n requestType\n }\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_POINT_COUNT = gql`\n query TranscendCliDataPointCount($filterBy: DataPointFiltersInput) {\n dataPoints(filterBy: $filterBy, useMaster: false) {\n totalCount\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - add orderBy\n// isExportCsv: true\nexport const SUB_DATA_POINTS = gql`\n query TranscendCliSubDataPoints(\n $filterBy: SubDataPointFiltersInput\n $first: Int!\n $offset: Int!\n ) {\n subDataPoints(filterBy: $filterBy, first: $first, offset: $offset, useMaster: false) {\n nodes {\n id\n name\n description\n purposes {\n name\n purpose\n }\n categories {\n name\n category\n }\n accessRequestVisibilityEnabled\n erasureRequestRedactionEnabled\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n }\n }\n }\n`;\n\nexport const SUB_DATA_POINTS_COUNT = gql`\n query TranscendCliSubDataPointsCount($filterBy: SubDataPointFiltersInput) {\n subDataPoints(filterBy: $filterBy, useMaster: false) {\n totalCount\n }\n }\n`;\n\nexport const SUB_DATA_POINTS_WITH_GUESSES = gql`\n query TranscendCliSubDataPointGuesses(\n $filterBy: SubDataPointFiltersInput\n $first: Int!\n $offset: Int!\n ) {\n subDataPoints(filterBy: $filterBy, first: $first, offset: $offset, useMaster: false) {\n nodes {\n id\n name\n description\n purposes {\n name\n purpose\n }\n categories {\n name\n category\n }\n pendingCategoryGuesses {\n category {\n name\n category\n }\n status\n confidence\n classifierVersion\n }\n accessRequestVisibilityEnabled\n erasureRequestRedactionEnabled\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n }\n }\n }\n`;\n\nexport const UPDATE_OR_CREATE_DATA_POINT = gql`\n mutation TranscendCliUpdateOrCreateDataPoint(\n $dataSiloId: ID!\n $name: String!\n $path: [String!]\n $title: String\n $description: String\n $ownerIds: [ID!]\n $ownerEmails: [String!]\n $teamNames: [String!]\n $teamIds: [ID!]\n $dataCollectionTag: String\n $querySuggestions: [DbIntegrationQuerySuggestionInput!]\n $enabledActions: [RequestActionObjectResolver!]\n $subDataPoints: [DataPointSubDataPointInput!]\n ) {\n updateOrCreateDataPoint(\n input: {\n dataSiloId: $dataSiloId\n name: $name\n path: $path\n title: $title\n teamNames: $teamNames\n ownerEmails: $ownerEmails\n dataCollectionTag: $dataCollectionTag\n description: $description\n ownerIds: $ownerIds\n teamIds: $teamIds\n querySuggestions: $querySuggestions\n enabledActions: $enabledActions\n subDataPoints: $subDataPoints\n }\n ) {\n dataPoint {\n id\n name\n }\n }\n }\n`;\n\nexport const DATAPOINT_EXPORT = gql`\n query TranscendCliDataPointCsvExport($filterBy: DataPointFiltersInput, $first: Int!) {\n dataPoints(filterBy: $filterBy, first: $first, useMaster: false) {\n nodes {\n id\n title {\n defaultMessage\n }\n description {\n defaultMessage\n }\n owners {\n email\n }\n teams {\n name\n }\n name\n path\n }\n }\n }\n`;\n","import {\n ConfidenceLabel,\n DataCategoryType,\n ProcessingPurpose,\n RequestActionObjectResolver,\n SubDataPointDataSubCategoryGuessStatus,\n} from '@transcend-io/privacy-types';\nimport { map, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { sortBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport type { DataSiloAttributeValue } from './fetchAllDataSilos.js';\nimport { DATA_POINTS, SUB_DATA_POINTS, SUB_DATA_POINTS_WITH_GUESSES } from './gqls/dataPoint.js';\n\nexport interface SubDataPointCategory {\n /** Sub-category name */\n name: string;\n /** Top-level category */\n category: DataCategoryType;\n}\n\nexport interface SubDataPointPurpose {\n /** Sub-purpose name */\n name: string;\n /** Top-level purpose */\n purpose: ProcessingPurpose;\n}\n\nexport interface SubDataPoint {\n /** Name (or key) of the subdatapoint */\n name: string;\n /** The description */\n description?: string;\n /** Personal data category */\n categories: SubDataPointCategory[];\n /** The processing purpose for this sub datapoint */\n purposes: SubDataPointPurpose[];\n /**\n * When true, this subdatapoint should be revealed in a data access request.\n * When false, this field should be redacted\n */\n accessRequestVisibilityEnabled: boolean;\n /**\n * When true, this subdatapoint should be redacted during an erasure request.\n * There normally is a choice of enabling hard deletion or redaction at the\n * datapoint level, but if redaction is enabled, this column can be used\n * to define which fields should be redacted.\n */\n erasureRequestRedactionEnabled: boolean;\n /** Attribute attached to subdatapoint */\n attributeValues: DataSiloAttributeValue[];\n /** Data category guesses that are output by the classifier */\n pendingCategoryGuesses?: {\n /** Data category being guessed */\n category: SubDataPointCategory;\n /** Status of guess */\n status: SubDataPointDataSubCategoryGuessStatus;\n /** Confidence level of guess */\n confidence: number;\n /** Confidence label */\n confidenceLabel: ConfidenceLabel;\n /** classifier version that produced the guess */\n classifierVersion: number;\n }[];\n}\n\nexport interface DataPoint {\n /** ID of dataPoint */\n id: string;\n /** Title of dataPoint */\n title: {\n /** Default message */\n defaultMessage: string;\n };\n /** The path to this data point */\n path: string[];\n /** Description */\n description: {\n /** Default message */\n defaultMessage: string;\n };\n /** Name */\n name: string;\n /** Global actions */\n actionSettings: {\n /** Action type */\n type: RequestActionObjectResolver;\n /** Is enabled */\n active: boolean;\n }[];\n /** Data collection tag for privacy request download zip labeling */\n dataCollection?: {\n /** Title of data collection */\n title: {\n /** Default message (since message can be translated) */\n defaultMessage: string;\n };\n };\n /** Metadata for this data silo */\n catalog: {\n /** Whether the data silo supports automated vendor coordination */\n hasAvcFunctionality: boolean;\n };\n /** Owners of the datapoint */\n owners: {\n /** Email address of the owner */\n email: string;\n }[];\n /** Teams that own the datapoint */\n teams: {\n /** Name of the team */\n name: string;\n }[];\n /** Database integration queries */\n dbIntegrationQueries: {\n /** Approved query */\n query: string | null;\n /** Suggested query */\n suggestedQuery: string | null;\n /** Request action */\n requestType: RequestActionObjectResolver;\n }[];\n}\n\nexport interface DataPointWithSubDataPoint extends DataPoint {\n /** The associated subdatapoints */\n subDataPoints: SubDataPoint[];\n}\n\n/**\n * Helper to fetch all subdatapoints for a given datapoint\n *\n * @param client - The GraphQL client\n * @param dataPointId - The datapoint ID\n * @param options - Options\n * @returns The list of subdatapoints\n */\nexport async function fetchAllSubDataPoints(\n client: GraphQLClient,\n options: {\n /** Filter criteria */\n filterBy: {\n /** Datapoint ID to fetch sub-datapoints for */\n dataPointId: string;\n };\n /** Enable debug logging */\n debug?: boolean;\n /** Page size for paginated fetching */\n pageSize: number;\n /** When true, metadata around guessed data categories should be included */\n includeGuessedCategories?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<SubDataPoint[]> {\n const {\n filterBy: { dataPointId },\n debug,\n includeGuessedCategories,\n pageSize,\n logger = NOOP_LOGGER,\n } = options;\n const subDataPoints: SubDataPoint[] = [];\n\n let offset = 0;\n\n let shouldContinue = false;\n do {\n try {\n if (debug) {\n logger.info(`Pulling in subdatapoints for offset ${offset}`);\n }\n const {\n subDataPoints: { nodes },\n } = await makeGraphQLRequest<{\n /** Query response */\n subDataPoints: {\n /** List of matches */\n nodes: SubDataPoint[];\n };\n }>(client, includeGuessedCategories ? SUB_DATA_POINTS_WITH_GUESSES : SUB_DATA_POINTS, {\n variables: {\n first: pageSize,\n filterBy: {\n dataPoints: [dataPointId],\n },\n offset,\n },\n logger,\n });\n\n subDataPoints.push(...nodes);\n offset += pageSize;\n shouldContinue = nodes.length === pageSize;\n\n if (debug) {\n logger.info(`Pulled in subdatapoints for offset ${offset} for dataPointId=${dataPointId}`);\n }\n } catch (err) {\n logger.error(\n `An error fetching subdatapoints for offset ${offset} for dataPointId=${dataPointId}`,\n );\n throw err;\n }\n } while (shouldContinue);\n return sortBy(subDataPoints, 'name');\n}\n\n/**\n * Fetch all datapoints for a data silo\n *\n * @param client - GraphQL client\n * @param dataSiloId - Data silo ID\n * @param options - Options\n * @returns List of datapoints\n */\nexport async function fetchAllDataPoints(\n client: GraphQLClient,\n options: {\n /** Filter criteria */\n filterBy: {\n /** Data silo ID to fetch datapoints for */\n dataSiloId: string;\n };\n /** Enable debug logging */\n debug?: boolean;\n /** Page size for paginated fetching */\n pageSize: number;\n /** Skip fetching of subdatapoints */\n skipSubDatapoints?: boolean;\n /** When true, metadata around guessed data categories should be included */\n includeGuessedCategories?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<DataPointWithSubDataPoint[]> {\n const {\n filterBy: { dataSiloId },\n debug,\n pageSize,\n skipSubDatapoints,\n includeGuessedCategories,\n logger = NOOP_LOGGER,\n } = options;\n const dataPoints: DataPointWithSubDataPoint[] = [];\n\n // TODO: https://transcend.height.app/T-40481 - add cursor pagination\n let offset = 0;\n\n let shouldContinue = false;\n do {\n if (debug) {\n logger.info(`Fetching datapoints with offset: ${offset}`);\n }\n\n const {\n dataPoints: { nodes },\n } = await makeGraphQLRequest<{\n /** Query response */\n dataPoints: {\n /** List of matches */\n nodes: DataPoint[];\n };\n }>(client, DATA_POINTS, {\n variables: {\n first: pageSize,\n filterBy: {\n dataSilos: [dataSiloId],\n },\n offset,\n },\n logger,\n });\n\n if (debug) {\n logger.info(`Fetched ${nodes.length} datapoints at offset: ${offset}`);\n }\n\n if (!skipSubDatapoints) {\n await map(\n nodes,\n async (node) => {\n try {\n if (debug) {\n logger.info(`Fetching subdatapoints for ${node.name} for datapoint offset ${offset}`);\n }\n\n const subDataPoints = await fetchAllSubDataPoints(client, {\n filterBy: { dataPointId: node.id },\n pageSize: 1000,\n debug,\n includeGuessedCategories,\n logger,\n });\n dataPoints.push({\n ...node,\n subDataPoints: subDataPoints.sort((a, b) => a.name.localeCompare(b.name)),\n });\n\n if (debug) {\n logger.info(`Successfully fetched subdatapoints for ${node.name}`);\n }\n } catch (err) {\n logger.error(\n `An error fetching subdatapoints for ${node.name} datapoint offset ${offset}`,\n );\n throw err;\n }\n },\n {\n concurrency: 5,\n },\n );\n\n if (debug) {\n logger.info(`Fetched all subdatapoints for page of datapoints at offset: ${offset}`);\n }\n }\n\n offset += pageSize;\n shouldContinue = nodes.length === pageSize;\n } while (shouldContinue);\n return dataPoints.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_SILOS = gql`\n query TranscendCliDataSilos($filterBy: DataSiloFiltersInput!, $first: Int!, $offset: Int!) {\n dataSilos(\n filterBy: $filterBy\n first: $first\n offset: $offset\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n useMaster: false\n ) {\n nodes {\n id\n title\n link\n type\n catalog {\n hasAvcFunctionality\n }\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_SILO_EXPORT = gql`\n query TranscendCliDataSiloExport($filterBy: DataSiloFiltersInput!, $first: Int!) {\n dataSilos(filterBy: $filterBy, first: $first, useMaster: false) {\n nodes {\n id\n title\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_SILOS_ENRICHED = gql`\n query TranscendCliDataSilosEnriched(\n $filterBy: DataSiloFiltersInput!\n $first: Int!\n $offset: Int!\n ) {\n dataSilos(\n filterBy: $filterBy\n first: $first\n offset: $offset\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n useMaster: false\n ) {\n nodes {\n id\n title\n description\n type\n outerType\n link\n country\n countrySubDivision\n url\n notifyEmailAddress\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n apiKeys {\n title\n }\n subjectBlocklist {\n type\n }\n identifiers {\n name\n isConnected\n }\n dependentDataSilos {\n title\n }\n owners {\n email\n }\n teams {\n id\n name\n }\n catalog {\n hasAvcFunctionality\n }\n isLive\n promptAVendorEmailSendFrequency\n promptAVendorEmailSendType\n promptAVendorEmailIncludeIdentifiersAttachment\n promptAVendorEmailCompletionLinkType\n manualWorkRetryFrequency\n discoveredBy {\n title\n }\n businessEntities {\n title\n }\n }\n }\n }\n`;\n\nexport const UPDATE_DATA_SILOS = gql`\n mutation TranscendCliUpdateDataSilo($input: UpdateDataSilosInput!) {\n updateDataSilos(input: $input) {\n clientMutationId\n dataSilos {\n id\n title\n }\n }\n }\n`;\n\nexport const CREATE_DATA_SILOS = gql`\n mutation TranscendCliCreateDataSilo($input: [CreateDataSilosInput!]!) {\n createDataSilos(input: $input) {\n dataSilos {\n id\n title\n }\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport type { DataSiloAttributeValue } from '../dsr-automation/formatAttributeValues.js';\nimport { DATA_SILOS } from './gqls/dataSilo.js';\n\nexport type { DataSiloAttributeValue };\n\nexport interface DataSilo {\n /** ID of dataSilo */\n id: string;\n /** Title of dataSilo */\n title: string;\n /** Type of silo */\n type: string;\n /** The link to the data silo */\n link: string;\n /** Attribute labels */\n attributeValues: DataSiloAttributeValue[];\n /** description */\n description: string;\n /** Metadata for this data silo */\n catalog: {\n /** Whether the data silo supports automated vendor coordination */\n hasAvcFunctionality: boolean;\n };\n}\n\n/**\n * Fetch all dataSilos in the organization\n *\n * @param client - GraphQL client\n * @param options - Filter and pagination options\n * @returns All dataSilos in the organization\n */\nexport async function fetchAllDataSilos<TDataSilo extends DataSilo>(\n client: GraphQLClient,\n options: {\n /** Page size to fetch data silos in */\n pageSize: number;\n /** Filter by title */\n titles?: string[];\n /** Filter by IDs */\n ids?: string[];\n /** Set of integration names to fetch */\n integrationNames?: string[];\n /** GQL query override for data silos */\n gql?: string;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<TDataSilo[]> {\n const {\n titles,\n pageSize,\n ids = [],\n gql = DATA_SILOS,\n integrationNames = [],\n logger = NOOP_LOGGER,\n } = options;\n\n logger.info(`Fetching ${ids.length === 0 ? 'all' : ids.length} Data Silos...`);\n\n const dataSilos: TDataSilo[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n dataSilos: { nodes },\n } = await makeGraphQLRequest<{\n /** Query response */\n dataSilos: {\n /** List of matches */\n nodes: TDataSilo[];\n };\n }>(client, gql, {\n variables: {\n filterBy: {\n ids: ids.length > 0 ? ids : undefined,\n type: integrationNames.length > 0 ? integrationNames : undefined,\n titles,\n },\n first: pageSize,\n offset,\n },\n logger,\n });\n dataSilos.push(...nodes);\n offset += pageSize;\n shouldContinue = nodes.length === pageSize;\n } while (shouldContinue);\n\n logger.info(\n `Found a total of ${dataSilos.length} data silo${\n ids.length > 0 ? ` matching IDs ${ids.join(',')}` : ''\n }s${\n integrationNames.length > 0 ? ` matching integrationNames ${integrationNames.join(',')}` : ''\n }`,\n );\n\n return dataSilos.sort((a, b) => a.title.localeCompare(b.title));\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const IDENTIFIERS: DocumentNode = parse(gql`\n query TranscendCliIdentifiers($first: Int!, $offset: Int!) {\n identifiers(\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n type\n regex\n selectOptions\n privacyCenterVisibility\n dataSubjects {\n type\n }\n isRequiredInForm\n placeholder\n displayTitle {\n defaultMessage\n }\n displayDescription {\n defaultMessage\n }\n displayOrder\n isUniqueOnPreferenceStore\n }\n }\n }\n`);\n","import { IdentifierType, RequestAction } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { IDENTIFIERS } from './gqls/identifier.js';\n\nexport interface Identifier {\n /** ID of identifier */\n id: string;\n /** Name of identifier */\n name: string;\n /** The type of identifier */\n type: IdentifierType;\n /** Regular expression */\n regex: string;\n /** The set of options that the identifier supports */\n selectOptions: string[];\n /** Whether identifier is enabled on privacy center */\n privacyCenterVisibility: RequestAction[];\n /** Enabled data subjects that are exposed this identifier on the privacy center */\n dataSubjects: {\n /** type of data subjects */\n type: string;\n }[];\n /** Whether identifier is a required field in privacy center form */\n isRequiredInForm: boolean;\n /** Identifier placeholder text */\n placeholder: string;\n /** Display title for identifier */\n displayTitle: {\n /** Default message */\n defaultMessage: string;\n };\n /** Display description for identifier */\n displayDescription: {\n /** Default */\n defaultMessage: string;\n };\n /** Display order */\n displayOrder: number;\n /** Does this identifier uniquely identify a consent record */\n isUniqueOnPreferenceStore: boolean;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all identifiers in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All identifiers in the organization\n */\nexport async function fetchAllIdentifiers(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Identifier[]> {\n const { logger } = options;\n const identifiers: Identifier[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n identifiers: { nodes },\n } = await makeGraphQLRequest<{\n /** Identifiers */\n identifiers: {\n /** List */\n nodes: Identifier[];\n };\n }>(client, IDENTIFIERS, {\n logger,\n variables: { first: PAGE_SIZE, offset },\n });\n identifiers.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return identifiers.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\nexport const PROCESSING_ACTIVITIES = gql`\n query TranscendCliProcessingActivities($first: Int!, $offset: Int!) {\n processingActivities(first: $first, offset: $offset, useMaster: false) {\n nodes {\n id\n title\n description\n securityMeasureDetails\n controllerships\n storageRegions {\n countrySubDivision\n country\n }\n transferRegions {\n countrySubDivision\n country\n }\n retentionType\n retentionPeriod\n dataProtectionImpactAssessmentLink\n dataProtectionImpactAssessmentStatus\n attributeValues {\n name\n attributeKey {\n name\n }\n }\n dataSilos {\n title\n }\n dataSubjects {\n type\n }\n teams {\n name\n }\n owners {\n email\n }\n processingPurposeSubCategories {\n name\n purpose\n }\n dataSubCategories {\n name\n category\n }\n saaSCategories {\n title\n }\n }\n }\n }\n`;\n\nexport const CREATE_PROCESSING_ACTIVITY = gql`\n mutation TranscendCliCreateProcessingActivity($input: CreateProcessingActivityInput!) {\n createProcessingActivity(input: $input) {\n processingActivity {\n id\n title\n }\n }\n }\n`;\n\nexport const UPDATE_PROCESSING_ACTIVITIES = gql`\n mutation TranscendCliUpdateProcessingActivities($input: UpdateProcessingActivitiesInput!) {\n updateProcessingActivities(input: $input) {\n clientMutationId\n }\n }\n`;\n","import type {\n ProcessingPurpose,\n DataCategoryType,\n DataProtectionImpactAssessmentStatus,\n Controllership,\n RetentionType,\n} from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport type { Region } from '../administration/formatRegions.js';\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PROCESSING_ACTIVITIES } from './gqls/processingActivity.js';\n\nexport interface ProcessingActivity {\n /** ID of processing activity */\n id: string;\n /** Title of processing activity */\n title: string;\n /** Description of processing activity */\n description: string;\n /** Security measure details */\n securityMeasureDetails?: string;\n /** Controllerships */\n controllerships: Controllership[];\n /** Storage regions */\n storageRegions: Region[];\n /** Transfer regions */\n transferRegions: Region[];\n /** Retention type */\n retentionType: RetentionType;\n /** Retention period in days */\n retentionPeriod?: number;\n /** Data protection impact assessment link */\n dataProtectionImpactAssessmentLink?: string;\n /** Data protection impact assessment status */\n dataProtectionImpactAssessmentStatus: DataProtectionImpactAssessmentStatus;\n /** Attribute values */\n attributeValues: {\n /** Name of attribute value */\n name: string;\n /** Attribute key */\n attributeKey: {\n /** Name of attribute key */\n name: string;\n };\n }[];\n /** Data silos */\n dataSilos: {\n /** Data silo title */\n title: string;\n }[];\n /** Data subjects */\n dataSubjects: {\n /** Data subject type */\n type: string;\n }[];\n /** Teams */\n teams: {\n /** Team name */\n name: string;\n }[];\n /** Owners */\n owners: {\n /** Owner email */\n email: string;\n }[];\n /** Processing purpose sub categories */\n processingPurposeSubCategories: {\n /** Processing purpose sub category name */\n name: string;\n /** Processing purpose */\n purpose: ProcessingPurpose;\n }[];\n /** Data sub categories */\n dataSubCategories: {\n /** Data sub category name */\n name: string;\n /** Data category */\n category: DataCategoryType;\n }[];\n /** SaaS categories */\n saaSCategories: {\n /** Title */\n title: string;\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all processingActivities in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All processingActivities in the organization\n */\nexport async function fetchAllProcessingActivities(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<ProcessingActivity[]> {\n const { logger } = options;\n const processingActivities: ProcessingActivity[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n processingActivities: { nodes },\n } = await makeGraphQLRequest<{\n /** Processing activities */\n processingActivities: {\n /** List */\n nodes: ProcessingActivity[];\n };\n }>(client, PROCESSING_ACTIVITIES, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n processingActivities.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return processingActivities.sort((a, b) => a.title.localeCompare(b.title));\n}\n","import { gql } from 'graphql-request';\n\nexport const VENDORS = gql`\n query TranscendCliVendors($first: Int!, $offset: Int!) {\n vendors(\n first: $first\n offset: $offset\n useMaster: false\n isExportCsv: true\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n ) {\n nodes {\n id\n title\n description\n dataProcessingAgreementLink\n contactName\n contactEmail\n contactPhone\n address\n headquarterCountry\n headquarterSubDivision\n websiteUrl\n businessEntity {\n title\n }\n teams {\n name\n }\n owners {\n email\n }\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n }\n }\n }\n`;\n\nexport const CREATE_VENDOR = gql`\n mutation TranscendCliCreateVendor($input: CreateVendorInput!) {\n createVendor(input: $input) {\n vendor {\n id\n title\n }\n }\n }\n`;\n\nexport const UPDATE_VENDORS = gql`\n mutation TranscendCliUpdateVendor($input: UpdateVendorsInput!) {\n updateVendors(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { IsoCountryCode, IsoCountrySubdivisionCode } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { VENDORS } from './gqls/vendor.js';\n\nexport interface Vendor {\n /** ID of vendor */\n id: string;\n /** Title of vendor */\n title: string;\n /** Description of vendor */\n description: string;\n /** DPA link */\n dataProcessingAgreementLink?: string;\n /** Contract email */\n contactName?: string;\n /** Contract phone */\n contactPhone?: string;\n /** Address */\n address?: string;\n /** Headquarters country */\n headquarterCountry?: IsoCountryCode;\n /** Headquarters subdivision */\n headquarterSubDivision?: IsoCountrySubdivisionCode;\n /** Website URL */\n websiteUrl?: string;\n /** Business entity */\n businessEntity?: {\n /** Business entity title */\n title: string;\n };\n /** Assigned teams */\n teams: {\n /** Team name */\n name: string;\n }[];\n /** Assigned owners */\n owners: {\n /** Email */\n email: string;\n }[];\n /** Custom fields */\n attributeValues: {\n /** Name of attribute value */\n name: string;\n /** Attribute key that the value represents */\n attributeKey: {\n /** Name of attribute team */\n name: string;\n };\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all vendors in the organization\n *\n * @param client - GraphQL client\n * @returns All vendors in the organization\n */\nexport async function fetchAllVendors(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Vendor[]> {\n const { logger } = options;\n const vendors: Vendor[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n vendors: { nodes },\n } = await makeGraphQLRequest<{\n /** Vendors */\n vendors: {\n /** List */\n nodes: Vendor[];\n };\n }>(client, VENDORS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n vendors.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return vendors.sort((a, b) => a.title.localeCompare(b.title));\n}\n","import {\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n PromptAVendorEmailCompletionLinkType,\n PromptAVendorEmailSendType,\n} from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllDataPoints, type DataPointWithSubDataPoint } from './fetchAllDataPoints.js';\nimport { fetchAllDataSilos, type DataSiloAttributeValue } from './fetchAllDataSilos.js';\nimport { DATA_SILOS_ENRICHED } from './gqls/dataSilo.js';\n\nexport interface DataSiloEnriched {\n /** ID of dataSilo */\n id: string;\n /** Title of dataSilo */\n title: string;\n /** Type of silo */\n type: string;\n /** Link to silo */\n link: string;\n /** Outer type of silo */\n outerType: string;\n /** Description of data silo */\n description: string;\n /** Webhook URL */\n url?: string;\n /** Email address of user to notify for prompt a person use case */\n notifyEmailAddress?: string;\n /** Associated API keys */\n apiKeys: {\n /** Title */\n title: string;\n }[];\n /** Data subject block list */\n subjectBlocklist: {\n /** Type of data subject */\n type: string;\n }[];\n /** Identifiers */\n identifiers: {\n /** Name of identifier */\n name: string;\n /** True if identifier is wired */\n isConnected: boolean;\n }[];\n /** Dependent data silos */\n dependentDataSilos: {\n /** Title of silo */\n title: string;\n }[];\n /** Silo owners */\n owners: {\n /** Email owners */\n email: string;\n }[];\n /** The teams assigned to this data silo */\n teams: {\n /** Name of the team assigned to this data silo */\n name: string;\n }[];\n /** Metadata for this data silo */\n catalog: {\n /** Whether the data silo supports automated vendor coordination */\n hasAvcFunctionality: boolean;\n };\n /** Silo is live */\n isLive: boolean;\n /** Hosting country of data silo */\n country?: IsoCountryCode;\n /** Hosting subdivision data silo */\n countrySubDivision?: IsoCountrySubdivisionCode;\n /**\n * The frequency with which we should be sending emails for this data silo, in milliseconds.\n */\n promptAVendorEmailSendFrequency: number;\n /**\n * The type of emails to send for this data silo, i.e. send an email for each DSR, across all open DSRs,\n * or per profile in a DSR.\n */\n promptAVendorEmailSendType: PromptAVendorEmailSendType;\n /**\n * Indicates whether prompt-a-vendor emails should include a list of identifiers\n * in addition to a link to the bulk processing UI.\n */\n promptAVendorEmailIncludeIdentifiersAttachment: boolean;\n /**\n * Indicates what kind of link to generate as part of the emails sent out for this Prompt-a-Vendor silo.\n */\n promptAVendorEmailCompletionLinkType: PromptAVendorEmailCompletionLinkType;\n /**\n * The frequency with which we should retry sending emails for this data silo, in milliseconds.\n * Needs to be a string because the number can be larger than the MAX_INT\n */\n manualWorkRetryFrequency: string;\n /** Attribute values tagged to data silo */\n attributeValues: DataSiloAttributeValue[];\n /**\n * The data silos that discovered this particular data silo\n */\n discoveredBy: {\n /** Title of data silo */\n title: string;\n }[];\n /**\n * The business entities assigned directly to this data silo\n */\n businessEntities: {\n /** Title of business entity */\n title: string;\n }[];\n}\n\n/**\n * Fetch all dataSilos with additional metadata\n *\n * @param client - GraphQL client\n * @param options - Filter options\n * @returns All dataSilos in the organization\n */\nexport async function fetchEnrichedDataSilos(\n client: GraphQLClient,\n options: {\n /** Page size */\n pageSize: number;\n /** Filter by IDs */\n ids?: string[];\n /** Enable debug logs */\n debug?: boolean;\n /** Filter by title */\n titles?: string[];\n /** Integration names */\n integrationNames?: string[];\n /** Skip fetching of datapoints */\n skipDatapoints?: boolean;\n /** Skip fetching of subdatapoints */\n skipSubDatapoints?: boolean;\n /** When true, metadata around guessed data categories should be included */\n includeGuessedCategories?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<[DataSiloEnriched, DataPointWithSubDataPoint[]][]> {\n const {\n ids,\n pageSize,\n titles,\n debug,\n skipDatapoints,\n skipSubDatapoints,\n includeGuessedCategories,\n integrationNames,\n logger = NOOP_LOGGER,\n } = options;\n\n const dataSilos: [DataSiloEnriched, DataPointWithSubDataPoint[]][] = [];\n\n const silos = await fetchAllDataSilos<DataSiloEnriched>(client, {\n titles,\n ids,\n integrationNames,\n pageSize,\n gql: DATA_SILOS_ENRICHED,\n logger,\n });\n\n if (!skipDatapoints) {\n await mapSeries(silos, async (silo, index) => {\n logger.info(`[${index + 1}/${silos.length}] Fetching data silo - ${silo.title}`);\n\n const dataPoints = await fetchAllDataPoints(client, {\n filterBy: { dataSiloId: silo.id },\n debug,\n pageSize,\n skipSubDatapoints,\n includeGuessedCategories,\n logger,\n });\n\n if (debug) {\n logger.info(\n `[${index + 1}/${silos.length}] Successfully fetched datapoint for - ${silo.title}`,\n );\n }\n\n dataSilos.push([silo, dataPoints]);\n });\n }\n\n logger.info(`Successfully fetched all ${silos.length} data silo configurations`);\n\n return dataSilos;\n}\n","import { IsoCountryCode, IsoCountrySubdivisionCode } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy, chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllBusinessEntities, type BusinessEntity } from './fetchAllBusinessEntities.js';\nimport { UPDATE_BUSINESS_ENTITIES, CREATE_BUSINESS_ENTITY } from './gqls/businessEntity.js';\n\nexport interface BusinessEntityInput {\n /** Display title of the business entity */\n title: string;\n /** Description of the business entity */\n description?: string;\n /** Physical address */\n address?: string;\n /** Headquarters country */\n headquarterCountry?: IsoCountryCode;\n /** Headquarters country subdivision */\n headquarterSubDivision?: IsoCountrySubdivisionCode;\n /** Name of the data protection officer */\n dataProtectionOfficerName?: string;\n /** Email of the data protection officer */\n dataProtectionOfficerEmail?: string;\n /** Custom attribute values to assign */\n attributes?: {\n /** Attribute key name */\n key: string;\n /** Attribute values */\n values: string[];\n }[];\n /** Team names to assign */\n teams?: string[];\n /** Owner email addresses to assign */\n owners?: string[];\n}\n\n/**\n * Input to create a new business entity\n *\n * @param client - GraphQL client\n * @param businessEntity - Input\n * @returns Created business entity\n */\nexport async function createBusinessEntity(\n client: GraphQLClient,\n options: {\n /** Business entity to create */\n input: BusinessEntityInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<BusinessEntity> {\n const { input: businessEntity, logger = NOOP_LOGGER } = options;\n const input = {\n title: businessEntity.title,\n description: businessEntity.description,\n address: businessEntity.address,\n headquarterCountry: businessEntity.headquarterCountry,\n headquarterSubDivision: businessEntity.headquarterSubDivision,\n dataProtectionOfficerName: businessEntity.dataProtectionOfficerName,\n dataProtectionOfficerEmail: businessEntity.dataProtectionOfficerEmail,\n attributes: businessEntity.attributes,\n teamNames: businessEntity.teams,\n ownerEmails: businessEntity.owners,\n };\n\n const { createBusinessEntity } = await makeGraphQLRequest<{\n /** Create business entity mutation */\n createBusinessEntity: {\n /** Created business entity */\n businessEntity: BusinessEntity;\n };\n }>(client, CREATE_BUSINESS_ENTITY, {\n variables: { input },\n logger,\n });\n return createBusinessEntity.businessEntity;\n}\n\n/**\n * Input to update business entities\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateBusinessEntities(\n client: GraphQLClient,\n options: {\n /** [BusinessEntityInput, businessEntityId] list */\n input: [BusinessEntityInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: businessEntities, logger = NOOP_LOGGER } = options;\n const chunkedUpdates = chunk(businessEntities, 100);\n await mapSeries(chunkedUpdates, async (chunked) => {\n await makeGraphQLRequest(client, UPDATE_BUSINESS_ENTITIES, {\n variables: {\n input: chunked.map(([businessEntity, id]) => ({\n id,\n title: businessEntity.title,\n description: businessEntity.description,\n address: businessEntity.address,\n headquarterCountry: businessEntity.headquarterCountry,\n headquarterSubDivision: businessEntity.headquarterSubDivision,\n dataProtectionOfficerName: businessEntity.dataProtectionOfficerName,\n dataProtectionOfficerEmail: businessEntity.dataProtectionOfficerEmail,\n attributes: businessEntity.attributes,\n teamNames: businessEntity.teams,\n ownerEmails: businessEntity.owners,\n })),\n },\n logger,\n });\n });\n}\n\n/**\n * Sync the data inventory business entities\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncBusinessEntities(\n client: GraphQLClient,\n inputs: BusinessEntityInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n // Fetch existing\n logger.info(`Syncing \"${inputs.length}\" business entities...`);\n\n let encounteredError = false;\n\n // Fetch existing\n const existingBusinessEntities = await fetchAllBusinessEntities(client, { logger });\n\n // Look up by title\n const businessEntityByTitle = keyBy(existingBusinessEntities, 'title');\n\n // Create new business entities\n const newBusinessEntities = inputs.filter((input) => !businessEntityByTitle[input.title]);\n\n // Create new business entities\n await mapSeries(newBusinessEntities, async (businessEntity) => {\n try {\n const newBusinessEntity = await createBusinessEntity(client, {\n input: businessEntity,\n logger,\n });\n businessEntityByTitle[newBusinessEntity.title] = newBusinessEntity;\n logger.info(`Successfully synced business entity \"${businessEntity.title}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to sync business entity \"${businessEntity.title}\"! - ${(err as Error).message}`,\n );\n }\n });\n\n // Update all business entities\n try {\n logger.info(`Updating \"${inputs.length}\" business entities!`);\n await updateBusinessEntities(client, {\n input: inputs.map((input) => [input, businessEntityByTitle[input.title]!.id]),\n logger,\n });\n logger.info(`Successfully synced \"${inputs.length}\" business entities!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to sync \"${inputs.length}\" business entities ! - ${(err as Error).message}`,\n );\n }\n\n return !encounteredError;\n}\n","import { DataCategoryType } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllDataCategories, type DataSubCategory } from './fetchAllDataCategories.js';\nimport { UPDATE_DATA_SUB_CATEGORIES, CREATE_DATA_SUB_CATEGORY } from './gqls/dataCategory.js';\n\nexport interface DataCategoryInput {\n /** Name of data category */\n name: string;\n /** Type of data category */\n category: DataCategoryType;\n /** Description of data category */\n description?: string;\n /** Regex for data category */\n regex?: string;\n /** Owner email addresses to assign */\n owners?: string[];\n /** Team names to assign */\n teams?: string[];\n /** Attribute value and its corresponding attribute key */\n attributes?: {\n /** Attribute key */\n key: string;\n /** Attribute values */\n values: string[];\n }[];\n}\n\n/**\n * Create a new data category\n *\n * @param client - GraphQL client\n * @param dataCategory - Input\n * @param options - Options\n * @returns Created data category\n */\nexport async function createDataCategory(\n client: GraphQLClient,\n options: {\n /** Data category to create */\n input: DataCategoryInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<DataSubCategory, 'id' | 'name' | 'category'>> {\n const { input: dataCategory, logger = NOOP_LOGGER } = options;\n const input = {\n name: dataCategory.name,\n category: dataCategory.category,\n description: dataCategory.description,\n // TODO: https://transcend.height.app/T-31994 - add attributes, teams, owners\n };\n\n const { createDataCategory } = await makeGraphQLRequest<{\n /** Create data category mutation */\n createDataCategory: {\n /** Created data category */\n dataCategory: DataSubCategory;\n };\n }>(client, CREATE_DATA_SUB_CATEGORY, {\n variables: { input },\n logger,\n });\n return createDataCategory.dataCategory;\n}\n\n/**\n * Update data categories\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateDataCategories(\n client: GraphQLClient,\n options: {\n /** [DataCategoryInput, dataCategoryId] list */\n input: [DataCategoryInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: dataCategories, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_DATA_SUB_CATEGORIES, {\n variables: {\n input: {\n dataSubCategories: dataCategories.map(([dataCategory, id]) => ({\n id,\n description: dataCategory.description,\n // TODO: https://transcend.height.app/T-31994 - add teams, owners\n attributes: dataCategory.attributes,\n })),\n },\n },\n logger,\n });\n}\n\n/**\n * Sync the data inventory data categories\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncDataCategories(\n client: GraphQLClient,\n inputs: DataCategoryInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n logger.info(`Syncing \"${inputs.length}\" data categories...`);\n\n let encounteredError = false;\n\n // Fetch existing\n const existingDataCategories = await fetchAllDataCategories(client, {\n logger,\n });\n\n // Look up by name\n const dataCategoryByName: {\n [k in string]: Pick<DataSubCategory, 'id' | 'name' | 'category'>;\n } = keyBy(existingDataCategories, ({ name, category }) => `${name}:${category}`);\n\n // Create new data categories\n const newDataCategories = inputs.filter(\n (input) => !dataCategoryByName[`${input.name}:${input.category}`],\n );\n\n await mapSeries(newDataCategories, async (dataCategory) => {\n try {\n const newDataCategory = await createDataCategory(client, { input: dataCategory, logger });\n dataCategoryByName[`${newDataCategory.name}:${newDataCategory.category}`] = newDataCategory;\n logger.info(`Successfully synced data category \"${dataCategory.name}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to sync data category \"${dataCategory.name}\"! - ${(err as Error).message}`,\n );\n }\n });\n\n // Update all data categories\n try {\n logger.info(`Updating \"${inputs.length}\" data categories!`);\n await updateDataCategories(client, {\n input: inputs.map((input) => [\n input,\n dataCategoryByName[`${input.name}:${input.category}`]!.id,\n ]),\n logger,\n });\n logger.info(`Successfully synced \"${inputs.length}\" data categories!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync \"${inputs.length}\" data categories ! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport type { DataSilo } from './fetchAllDataSilos.js';\nimport { UPDATE_DATA_SILOS } from './gqls/dataSilo.js';\n\nconst BATCH_SILOS_LIMIT = 20;\n\n/**\n * Sync data silo dependencies\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns True upon success\n */\nexport async function syncDataSiloDependencies(\n client: GraphQLClient,\n options: {\n /** Pairs of [data silo ID, dependency titles] */\n input: [string, string[]][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<boolean> {\n const { input: dependencyUpdates, logger = NOOP_LOGGER } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${dependencyUpdates.length}\" data silo dependencies...`);\n\n const chunkedUpdates = chunk(dependencyUpdates, BATCH_SILOS_LIMIT);\n await mapSeries(chunkedUpdates, async (dependencyUpdateChunk, ind) => {\n logger.info(\n `[Batch ${ind}/${dependencyUpdateChunk.length}] Updating \"${dependencyUpdateChunk.length}\" data silos...`,\n );\n try {\n await makeGraphQLRequest<{\n /** Mutation result */\n updateDataSilos: {\n /** New data silos */\n dataSilos: Pick<DataSilo, 'id' | 'title'>[];\n };\n }>(client, UPDATE_DATA_SILOS, {\n variables: {\n input: {\n dataSilos: dependencyUpdateChunk.map(([id, dependedOnDataSiloTitles]) => ({\n id,\n dependedOnDataSiloTitles,\n })),\n },\n },\n logger,\n });\n logger.info(\n `[Batch ${ind + 1}/${dependencyUpdateChunk.length}] ` +\n `Synced \"${dependencyUpdateChunk.length}\" data silos!`,\n );\n } catch (err) {\n encounteredError = true;\n logger.error(\n `[Batch ${ind + 1}/${dependencyUpdateChunk.length}] ` +\n `Failed to update \"${dependencyUpdateChunk.length}\" silos! - ${(err as Error).message}`,\n );\n }\n });\n return !encounteredError;\n}\n","import type {\n ProcessingPurpose,\n DataCategoryType,\n DataProtectionImpactAssessmentStatus,\n Controllership,\n RetentionType,\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n} from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport {\n fetchAllProcessingActivities,\n type ProcessingActivity,\n} from './fetchAllProcessingActivities.js';\nimport {\n UPDATE_PROCESSING_ACTIVITIES,\n CREATE_PROCESSING_ACTIVITY,\n} from './gqls/processingActivity.js';\n\nexport interface ProcessingActivityInput {\n /** The title of the processing activity */\n title: string;\n /** Description of the processing activity */\n description?: string;\n /** Security measure details */\n securityMeasureDetails?: string;\n /** Controllerships */\n controllerships?: Controllership[];\n /** Storage regions */\n storageRegions?: {\n /** The country */\n country?: IsoCountryCode;\n /** The country subdivision */\n countrySubDivision?: IsoCountrySubdivisionCode;\n }[];\n /** Transfer regions */\n transferRegions?: {\n /** The country */\n country?: IsoCountryCode;\n /** The country subdivision */\n countrySubDivision?: IsoCountrySubdivisionCode;\n }[];\n /** Retention type */\n retentionType?: RetentionType;\n /** Retention period in days */\n retentionPeriod?: number;\n /** Data protection impact assessment link */\n dataProtectionImpactAssessmentLink?: string;\n /** Data protection impact assessment status */\n dataProtectionImpactAssessmentStatus?: DataProtectionImpactAssessmentStatus;\n /** Attribute value and its corresponding attribute key */\n attributes?: {\n /** Attribute key */\n key: string;\n /** Attribute values */\n values: string[];\n }[];\n /** Data silo titles */\n dataSiloTitles?: string[];\n /** Data subject types */\n dataSubjectTypes?: string[];\n /** Team names */\n teamNames?: string[];\n /** Owner emails */\n ownerEmails?: string[];\n /** Processing sub purposes */\n processingSubPurposes?: {\n /** The parent purpose */\n purpose: ProcessingPurpose;\n /** User-defined name for this processing purpose sub category */\n name?: string;\n }[];\n /** Data sub categories */\n dataSubCategories?: {\n /** The parent category */\n category: DataCategoryType;\n /** User-defined name for this sub category */\n name?: string;\n }[];\n /** SaaS category titles */\n saaSCategories?: string[];\n}\n\n/**\n * Create a new processing activity, setting only title and description\n *\n * @param client - GraphQL client\n * @param processingActivity - Input\n * @param options - Options\n * @returns Created processingActivity\n */\nasync function createProcessingActivity(\n client: GraphQLClient,\n processingActivity: ProcessingActivityInput,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Pick<ProcessingActivity, 'id' | 'title'>> {\n const { logger = NOOP_LOGGER } = options;\n const input = {\n title: processingActivity.title,\n description: processingActivity.description,\n };\n\n const { createProcessingActivity } = await makeGraphQLRequest<{\n /** Create processingActivity mutation */\n createProcessingActivity: {\n /** Created processingActivity */\n processingActivity: ProcessingActivity;\n };\n }>(client, CREATE_PROCESSING_ACTIVITY, {\n variables: { input },\n logger,\n });\n return createProcessingActivity.processingActivity;\n}\n\n/**\n * Update a list of processing activities.\n *\n * @param client - GraphQL client\n * @param processingActivityIdPairs - [ProcessingActivityInput, processingActivityId] list\n * @param options - Options\n */\nasync function updateProcessingActivities(\n client: GraphQLClient,\n processingActivityIdPairs: [ProcessingActivityInput, string][],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n const { logger = NOOP_LOGGER } = options;\n const invalidProcessingActivityTitles = processingActivityIdPairs\n .filter(([, id]) => id === undefined)\n .map(([{ title }]) => title);\n if (invalidProcessingActivityTitles.length > 0) {\n throw new Error(\n `The following ${\n invalidProcessingActivityTitles.length\n } processing activities do not exist and thus can't be updated: \"${invalidProcessingActivityTitles.join(\n '\", \"',\n )}\"`,\n );\n }\n await makeGraphQLRequest(client, UPDATE_PROCESSING_ACTIVITIES, {\n variables: {\n input: {\n processingActivities: processingActivityIdPairs.map(\n ([\n { processingSubPurposes, dataSubCategories, saaSCategories, ...processingActivity },\n id,\n ]) => ({\n dataSubCategoryInputs: dataSubCategories?.map(({ category, name }) => ({\n category,\n name: name ?? '',\n })),\n processingPurposeSubCategoryInputs: processingSubPurposes?.map(({ purpose, name }) => ({\n purpose,\n name: name ?? 'Other',\n })),\n saaSCategoryTitles: saaSCategories,\n ...processingActivity,\n id,\n }),\n ),\n },\n },\n logger,\n });\n}\n\n/**\n * Sync the data inventory processing activities\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncProcessingActivities(\n client: GraphQLClient,\n inputs: ProcessingActivityInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n let encounteredError = false;\n\n // Fetch existing\n logger.info(`Syncing \"${inputs.length}\" processing activities...`);\n const existingProcessingActivities = await fetchAllProcessingActivities(client, { logger });\n\n // Look up by title\n const processingActivityByTitle: Record<string, Pick<ProcessingActivity, 'id' | 'title'>> = keyBy(\n existingProcessingActivities,\n 'title',\n );\n\n // Create new processingActivities\n const newProcessingActivities = inputs.filter((input) => !processingActivityByTitle[input.title]);\n if (newProcessingActivities.length > 0) {\n logger.info(`Creating \"${newProcessingActivities.length}\" new processing activities...`);\n }\n await mapSeries(newProcessingActivities, async (processingActivity) => {\n try {\n const newProcessingActivity = await createProcessingActivity(client, processingActivity, {\n logger,\n });\n processingActivityByTitle[newProcessingActivity.title] = newProcessingActivity;\n logger.info(`Successfully created processing activity \"${processingActivity.title}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to create processing activity \"${processingActivity.title}\"! - ${(err as Error).message}`,\n );\n }\n });\n\n // Update all processing activities\n try {\n logger.info(`Updating \"${inputs.length}\" processing activities!`);\n await updateProcessingActivities(\n client,\n inputs\n .map((input) => [input, processingActivityByTitle[input.title]?.id] as const)\n .filter((x): x is [ProcessingActivityInput, string] => !!x[1]),\n { logger },\n );\n logger.info(`Successfully synced \"${inputs.length}\" processingActivities!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to sync \"${inputs.length}\" processingActivities! - ${(err as Error).message}`,\n );\n }\n\n return !encounteredError;\n}\n","import { IsoCountryCode, IsoCountrySubdivisionCode } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllVendors, type Vendor } from './fetchAllVendors.js';\nimport { UPDATE_VENDORS, CREATE_VENDOR } from './gqls/vendor.js';\n\nexport interface VendorInput {\n /** Display title of the vendor */\n title: string;\n /** Description of the vendor */\n description?: string;\n /** URL to the data processing agreement */\n dataProcessingAgreementLink?: string;\n /** Name of the primary contact */\n contactName?: string;\n /** Phone number of the primary contact */\n contactPhone?: string;\n /** Physical address */\n address?: string;\n /** Headquarters country */\n headquarterCountry?: IsoCountryCode;\n /** Headquarters country subdivision */\n headquarterSubDivision?: IsoCountrySubdivisionCode;\n /** Vendor website URL */\n websiteUrl?: string;\n /** Title of the associated business entity */\n businessEntity?: string;\n /** Owner email addresses to assign */\n owners?: string[];\n /** Team names to assign */\n teams?: string[];\n /** Custom attribute values to assign */\n attributes?: {\n /** Attribute key name */\n key: string;\n /** Attribute values */\n values: string[];\n }[];\n}\n\n/**\n * Input to create a new vendor\n *\n * @param client - GraphQL client\n * @param vendor - Input\n * @returns Created vendor\n */\nexport async function createVendor(\n client: GraphQLClient,\n options: {\n /** Vendor to create */\n input: VendorInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<Vendor, 'id' | 'title'>> {\n const { input: vendor, logger = NOOP_LOGGER } = options;\n const input = {\n title: vendor.title,\n description: vendor.description,\n address: vendor.address,\n headquarterCountry: vendor.headquarterCountry,\n headquarterSubDivision: vendor.headquarterSubDivision,\n dataProcessingAgreementLink: vendor.dataProcessingAgreementLink,\n contactName: vendor.contactName,\n contactPhone: vendor.contactPhone,\n websiteUrl: vendor.websiteUrl,\n // TODO: https://transcend.height.app/T-31994 - add attributes, teams, owners\n };\n\n const { createVendor } = await makeGraphQLRequest<{\n /** Create vendor mutation */\n createVendor: {\n /** Created vendor */\n vendor: Vendor;\n };\n }>(client, CREATE_VENDOR, {\n variables: { input },\n logger,\n });\n return createVendor.vendor;\n}\n\n/**\n * Input to update vendors\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateVendors(\n client: GraphQLClient,\n options: {\n /** [VendorInput, vendorId] list */\n input: [VendorInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: vendors, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_VENDORS, {\n variables: {\n input: {\n vendors: vendors.map(([vendor, id]) => ({\n id,\n title: vendor.title,\n description: vendor.description,\n address: vendor.address,\n headquarterCountry: vendor.headquarterCountry,\n headquarterSubDivision: vendor.headquarterSubDivision,\n dataProcessingAgreementLink: vendor.dataProcessingAgreementLink,\n contactName: vendor.contactName,\n contactPhone: vendor.contactPhone,\n websiteUrl: vendor.websiteUrl,\n // TODO: https://transcend.height.app/T-31994 - add teams, owners\n attributes: vendor.attributes,\n })),\n },\n },\n logger,\n });\n}\n\n/**\n * Sync the data inventory vendors\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncVendors(\n client: GraphQLClient,\n inputs: VendorInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n // Fetch existing\n logger.info(`Syncing \"${inputs.length}\" vendors...`);\n\n let encounteredError = false;\n\n // Fetch existing\n const existingVendors = await fetchAllVendors(client, { logger });\n\n // Look up by title\n const vendorByTitle: { [k in string]: Pick<Vendor, 'id' | 'title'> } = keyBy(\n existingVendors,\n 'title',\n );\n\n // Create new vendors\n const newVendors = inputs.filter((input) => !vendorByTitle[input.title]);\n\n // Create new vendors\n await mapSeries(newVendors, async (vendor) => {\n try {\n const newVendor = await createVendor(client, { input: vendor, logger });\n vendorByTitle[newVendor.title] = newVendor;\n logger.info(`Successfully synced vendor \"${vendor.title}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync vendor \"${vendor.title}\"! - ${(err as Error).message}`);\n }\n });\n\n // Update all vendors\n try {\n logger.info(`Updating \"${inputs.length}\" vendors!`);\n await updateVendors(client, {\n input: inputs.map((input) => [input, vendorByTitle[input.title]!.id]),\n logger,\n });\n logger.info(`Successfully synced \"${inputs.length}\" vendors!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync \"${inputs.length}\" vendors ! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const PURPOSES: DocumentNode = parse(gql`\n query TranscendCliPurposes(\n $first: Int!\n $offset: Int!\n $filterBy: TrackingPurposeFiltersInput\n $input: TrackingPurposeInput!\n ) {\n purposes(first: $first, offset: $offset, filterBy: $filterBy, input: $input) {\n nodes {\n id\n name\n description\n defaultConsent\n trackingType\n configurable\n essential\n showInConsentManager\n isActive\n displayOrder\n optOutSignals\n deletedAt\n authLevel\n showInPrivacyCenter\n title\n }\n }\n }\n`);\n","import { UserPrivacySignalEnum } from '@transcend-io/airgap.js-types';\nimport { DefaultConsentOption, PreferenceStoreAuthLevel } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PURPOSES } from './gqls/purpose.js';\n\nexport interface Purpose {\n /** ID of purpose */\n id: string;\n /** Name of purpose */\n name: string;\n /** Description of purpose */\n description: string;\n /** Default consent status */\n defaultConsent: DefaultConsentOption;\n /** Slug of purpose */\n trackingType: string;\n /** Whether the purpose is configurable */\n configurable: boolean;\n /** Whether the purpose is essential */\n essential: boolean;\n /** Whether to show the purpose in the consent manager */\n showInConsentManager: boolean;\n /** Whether the purpose is active */\n isActive: boolean;\n /** Display order of the purpose */\n displayOrder: number;\n /** Opt-out signals for the purpose */\n optOutSignals: UserPrivacySignalEnum[];\n /** Whether the purpose is deleted */\n deletedAt?: string;\n /** Authorization level required for the purpose */\n authLevel: PreferenceStoreAuthLevel;\n /** Whether to show the purpose in the privacy center */\n showInPrivacyCenter: boolean;\n /** Title of the purpose */\n title: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all purposes in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All purposes in the organization\n */\nexport async function fetchAllPurposes(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** Whether to include deleted purposes */\n includeDeleted?: boolean;\n };\n } = {},\n): Promise<Purpose[]> {\n const { logger, filterBy: { includeDeleted = false } = {} } = options;\n const purposes: Purpose[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n purposes: { nodes },\n } = await makeGraphQLRequest<{\n /** Purposes */\n purposes: {\n /** List */\n nodes: Purpose[];\n };\n }>(client, PURPOSES, {\n logger,\n variables: { first: PAGE_SIZE, offset, input: { includeDeleted } },\n });\n purposes.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return purposes.sort((a, b) => a.trackingType.localeCompare(b.trackingType));\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const PREFERENCE_TOPICS: DocumentNode = parse(gql`\n query TranscendCliPreferenceTopics(\n $first: Int!\n $offset: Int!\n $filterBy: PreferenceTopicFilterInput\n ) {\n preferenceTopics(first: $first, offset: $offset, filterBy: $filterBy) {\n nodes {\n id\n slug\n type\n title {\n id\n defaultMessage\n }\n showInPrivacyCenter\n displayDescription {\n id\n defaultMessage\n }\n defaultConfiguration\n preferenceOptionValues {\n slug\n title {\n id\n defaultMessage\n }\n }\n purpose {\n trackingType\n }\n }\n }\n }\n`);\n","import { PreferenceTopicType } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PREFERENCE_TOPICS } from './gqls/preferenceTopic.js';\n\nexport interface PreferenceTopic {\n /** ID of preference topic */\n id: string;\n /** Slug of preference topic */\n slug: string;\n /** Title of topic */\n title: {\n /** ID */\n id: string;\n /** Default message */\n defaultMessage: string;\n };\n /** Whether to show in privacy center */\n showInPrivacyCenter: boolean;\n /** Description to display in privacy center */\n displayDescription: {\n /** ID */\n id: string;\n /** Default message */\n defaultMessage: string;\n };\n /** Type of preference topic */\n type: PreferenceTopicType;\n /** Default configuration */\n defaultConfiguration: string;\n /** Option values */\n preferenceOptionValues: {\n /** Slug of value */\n slug: string;\n /** Title of value */\n title: {\n /** ID */\n id: string;\n /** Default message */\n defaultMessage: string;\n };\n }[];\n /** Related purpose */\n purpose: {\n /** Slug */\n trackingType: string;\n };\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all preference topics in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All preference topics in the organization\n */\nexport async function fetchAllPreferenceTopics(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<PreferenceTopic[]> {\n const { logger } = options;\n const preferenceTopics: PreferenceTopic[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n preferenceTopics: { nodes },\n } = await makeGraphQLRequest<{\n /** Preference topics */\n preferenceTopics: {\n /** List */\n nodes: PreferenceTopic[];\n };\n }>(client, PREFERENCE_TOPICS, {\n logger,\n variables: { first: PAGE_SIZE, offset },\n });\n preferenceTopics.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return preferenceTopics.sort((a, b) =>\n `${a.slug}:${a.purpose.trackingType}`.localeCompare(`${b.slug}:${b.purpose.trackingType}`),\n );\n}\n","import type { Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\n\nimport { type PreferenceTopic, fetchAllPreferenceTopics } from './fetchAllPreferenceTopics.js';\nimport { type Purpose, fetchAllPurposes } from './fetchAllPurposes.js';\n\nexport interface PurposeWithPreferences extends Purpose {\n /** Topics */\n topics: PreferenceTopic[];\n}\n\n/**\n * Fetch all purposes and preferences\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns List of purposes with their preference topics\n */\nexport async function fetchAllPurposesAndPreferences(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<PurposeWithPreferences[]> {\n const [purposes, topics] = await Promise.all([\n fetchAllPurposes(client, options),\n fetchAllPreferenceTopics(client, options),\n ]);\n\n return purposes.map((purpose) => ({\n ...purpose,\n topics: topics.filter((topic) => topic.purpose.trackingType === purpose.trackingType),\n }));\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const CREATE_PREFERENCE_ACCESS_TOKENS: DocumentNode = parse(gql`\n mutation TranscendCliCreatePreferenceAccessTokens($input: CreatePrivacyCenterAccessTokensInput!) {\n createPrivacyCenterAccessTokens(input: $input) {\n nodes {\n token\n }\n }\n }\n`);\n","import type { SombraStandardScope } from '@transcend-io/privacy-types';\nimport { map, type Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\nimport { chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { CREATE_PREFERENCE_ACCESS_TOKENS } from './gqls/preferenceAccessTokens.js';\n\nexport interface PreferenceAccessTokenInput {\n /** Slug of data subject to authenticate as */\n subjectType: string;\n /** Scopes to grant */\n scopes: SombraStandardScope[];\n /** Expiration time in seconds */\n expiresIn?: number;\n /** Email address of user */\n email: string;\n /** Core identifier for the user */\n coreIdentifier?: string;\n}\n\nexport interface PreferenceAccessTokenInputWithIndex extends PreferenceAccessTokenInput {\n /** Index of the input record */\n index?: number;\n}\n\nconst MAX_BATCH_SIZE = 50;\n\n/**\n * Create preference access tokens for a single page of identifiers.\n *\n * @param client - GraphQL client\n * @param records - Inputs to sign\n * @param logger - Logger\n * @returns list of access tokens\n */\nasync function createPreferenceAccessTokensPage(\n client: GraphQLClient,\n records: PreferenceAccessTokenInput[],\n logger?: Logger,\n): Promise<string[]> {\n const {\n createPrivacyCenterAccessTokens: { nodes },\n } = await makeGraphQLRequest<{\n /** createPrivacyCenterAccessTokens mutation */\n createPrivacyCenterAccessTokens: {\n /** Nodes */\n nodes: {\n /** Token */\n token: string;\n }[];\n };\n }>(client, CREATE_PREFERENCE_ACCESS_TOKENS, {\n logger,\n variables: { input: { records } },\n });\n return nodes.map((node) => node.token);\n}\n\n/**\n * Create preference access tokens for the given identifiers.\n *\n * @see https://docs.transcend.io/docs/articles/preference-management/access-links\n * @param client - GraphQL client\n * @param options - Options\n * @returns list of access tokens/input identifiers\n */\nexport async function createPreferenceAccessTokens(\n client: GraphQLClient,\n options: {\n /** Records to create tokens for */\n records: PreferenceAccessTokenInputWithIndex[];\n /** Logger instance */\n logger?: Logger;\n /** Optional progress emitter */\n emitProgress?: (progress: number) => void;\n /** Number of concurrent requests to make (default: 10) */\n concurrency?: number;\n },\n): Promise<\n {\n /** Identifier for the record */\n input: PreferenceAccessTokenInputWithIndex;\n /** Access token */\n accessToken: string;\n }[]\n> {\n const { records, logger, emitProgress, concurrency = 10 } = options;\n\n let completed = 0;\n emitProgress?.(0);\n\n const results: {\n /** Identifier for the record */\n input: PreferenceAccessTokenInput;\n /** Access token */\n accessToken: string;\n }[] = [];\n\n await map(\n chunk(records, MAX_BATCH_SIZE),\n async (chunkedRecords) => {\n const tokens = await createPreferenceAccessTokensPage(\n client,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n chunkedRecords.map(({ index, ...rest }) => rest),\n logger,\n );\n const mappedResults = tokens.map((token, idx) => ({\n input: chunkedRecords[idx]!,\n accessToken: token,\n }));\n results.push(...mappedResults);\n completed += chunkedRecords.length;\n emitProgress?.(completed);\n },\n { concurrency },\n );\n\n return results;\n}\n","import { PreferenceQueryResponseItem } from '@transcend-io/privacy-types';\nimport * as t from 'io-ts';\n\n/**\n * New response codec for the query endpoint\n */\nexport const ConsentPreferenceResponse = t.intersection([\n t.type({\n nodes: t.array(PreferenceQueryResponseItem),\n }),\n t.partial({\n /** Cursor for next page (opaque) */\n cursor: t.string,\n }),\n]);\n\n/**\n * Type override\n */\nexport type ConsentPreferenceResponse = t.TypeOf<typeof ConsentPreferenceResponse>;\n\n/** Identifier filter (new shape) */\nexport type PreferenceIdentifier = {\n /** e.g., \"email\", \"phone\" */\n name: string;\n /** identifier value */\n value: string;\n};\n\n/** Filter shape for the new query endpoint */\nexport type PreferencesQueryFilter = {\n /** Identifiers to filter by */\n identifiers?: PreferenceIdentifier[];\n /** Consent collection time */\n timestampBefore?: string;\n /** Consent collection time */\n timestampAfter?: string;\n /** System updatedAt time */\n system?: {\n /** Updated before this time */\n updatedBefore?: string;\n /** Updated after this time */\n updatedAfter?: string;\n };\n};\n\n/** Which dimension we chunk on */\nexport type ChunkMode = 'timestamp' | 'updated';\n","import {\n PreferenceQueryResponseItem,\n PreferenceStoreIdentifier,\n PreferenceUpdateItem,\n} from '@transcend-io/privacy-types';\nimport * as t from 'io-ts';\n\nexport const PurposeRowMapping = t.type({\n /**\n * The slug or trackingType of the purpose to map to\n *\n * e.g. `Marketing`\n */\n purpose: t.string,\n /**\n * If the column maps to a preference instead of a purpose\n * this is the slug of the purpose.\n *\n * null value indicates that this column maps to the true/false\n * value of the purpose\n */\n preference: t.union([t.string, t.null]),\n /**\n * The mapping between each row value and purpose/preference value.\n *\n * e.g. for a boolean preference or purpose\n * {\n * 'true': true,\n * 'false': false,\n * '': true,\n * }\n *\n * or for a single or multi select preference\n * {\n * '': true,\n * 'value1': 'Value1',\n * 'value2': 'Value2',\n * }\n */\n valueMapping: t.record(t.string, t.union([t.string, t.boolean, t.null, t.undefined])),\n});\n\n/** Override type */\nexport type PurposeRowMapping = t.TypeOf<typeof PurposeRowMapping>;\n\n/**\n * Mapping of column name to purpose row mapping.\n * This is used to map each column in the CSV to the relevant purpose and preference definitions in\n * transcend.\n */\nexport const ColumnPurposeMap = t.record(t.string, PurposeRowMapping);\n\n/** Override type */\nexport type ColumnPurposeMap = t.TypeOf<typeof ColumnPurposeMap>;\n\nexport const IdentifierMetadataForPreference = t.type({\n /** The identifier name */\n name: t.string,\n /** Is unique on preference store */\n isUniqueOnPreferenceStore: t.boolean,\n});\n\n/** Override type */\nexport type IdentifierMetadataForPreference = t.TypeOf<typeof IdentifierMetadataForPreference>;\n\n/**\n * Mapping of identifier name to the column name in the CSV file.\n * This is used to map each identifier name to the column in the CSV file.\n */\nexport const ColumnIdentifierMap = t.record(t.string, IdentifierMetadataForPreference);\n\n/** Override type */\nexport type ColumnIdentifierMap = t.TypeOf<typeof ColumnIdentifierMap>;\n\n/** Mapping of a CSV column to a metadata key in the preference store. */\nexport const MetadataMapping = t.type({\n /** The metadata key name in the preference store */\n key: t.string,\n});\n\n/** Override type */\nexport type MetadataMapping = t.TypeOf<typeof MetadataMapping>;\n\n/** Record mapping CSV column names to metadata keys. */\nexport const ColumnMetadataMap = t.record(t.string, MetadataMapping);\n\n/** Override type */\nexport type ColumnMetadataMap = t.TypeOf<typeof ColumnMetadataMap>;\n\nexport const FileMetadataState = t.intersection([\n t.type({\n /**\n * Definition of how to map each column in the CSV to\n * the relevant purpose and preference definitions in transcend\n */\n columnToPurposeName: t.record(t.string, PurposeRowMapping),\n /** Last time the file was last parsed at */\n lastFetchedAt: t.string,\n /**\n * Mapping of userId to the rows in the file that need to be uploaded\n * These uploads are overwriting non-existent preferences and are safe\n */\n pendingSafeUpdates: t.record(t.string, t.record(t.string, t.string)),\n /**\n * Mapping of userId to the rows in the file that need to be uploaded\n * these records have conflicts with existing consent preferences\n */\n pendingConflictUpdates: t.record(\n t.string,\n t.type({\n record: PreferenceQueryResponseItem,\n row: t.record(t.string, t.string),\n }),\n ),\n /**\n * Mapping of userId to the rows in the file that can be skipped because\n * their preferences are already in the store\n */\n skippedUpdates: t.record(t.string, t.record(t.string, t.string)),\n }),\n t.partial({\n /** Determine which column name in file maps to consent record identifier to upload on */\n identifierColumn: t.string,\n /** Determine which column name in file maps to the timestamp */\n timestampColum: t.string,\n }),\n]);\n\n/** Override type */\nexport type FileMetadataState = t.TypeOf<typeof FileMetadataState>;\n\n/**\n * Schema-only state for a preference CSV file format.\n *\n * Unlike FileMetadataState this does NOT embed upload receipts — it only\n * describes how columns map to identifiers, purposes, timestamps, and metadata.\n */\nexport const FileFormatState = t.intersection([\n t.type({\n /** Maps each CSV column to its purpose/preference definition in Transcend */\n columnToPurposeName: ColumnPurposeMap,\n /** ISO 8601 timestamp of when this config was last generated or refreshed */\n lastFetchedAt: t.string,\n /** Maps each CSV column to the identifier it represents (e.g. email, userId) */\n columnToIdentifier: ColumnIdentifierMap,\n }),\n t.partial({\n /** CSV column whose values contain the consent timestamp */\n timestampColumn: t.string,\n /** Maps CSV columns to metadata keys stored alongside the preference record */\n columnToMetadata: ColumnMetadataMap,\n /** CSV columns that should be skipped during upload */\n columnsToIgnore: t.array(t.string),\n }),\n]);\n\n/** Override type */\nexport type FileFormatState = t.TypeOf<typeof FileFormatState>;\n\n/**\n * This is the type of the receipts that are stored in the file\n * that is used to track the state of the upload process.\n * It is used to resume the upload process from where it left off.\n * It is used to persist the state of the upload process across multiple runs.\n */\nexport const PreferenceUpdateMap = t.record(\n t.string,\n // This can either be true to indicate the record is pending\n // or it can be an object showing the object\n // We only return a fixed number of results to avoid\n // making the JSON file too large\n t.union([t.boolean, PreferenceUpdateItem]),\n);\n\n/** Override type */\nexport type PreferenceUpdateMap = t.TypeOf<typeof PreferenceUpdateMap>;\n\n/**\n * This is the type of the pending updates that are safe to run without\n * conflicts with existing consent preferences.\n *\n * Key is primaryKey of the record in the file.\n * The value is the row in the file that is safe to upload.\n */\nexport const PendingSafePreferenceUpdates = t.record(\n t.string,\n // This can either be true to indicate the record is safe\n // or it can be an object showing the object\n // We only return a fixed number of results to avoid\n // making the JSON file too large\n t.union([t.boolean, t.record(t.string, t.string)]),\n);\n\n/** Override type */\nexport type PendingSafePreferenceUpdates = t.TypeOf<typeof PendingSafePreferenceUpdates>;\n\n/**\n * These are the updates that failed to be uploaded to the API.\n */\nexport const FailingPreferenceUpdates = t.record(\n t.string,\n t.type({\n /** Time upload ran at */\n uploadedAt: t.string,\n /** Attempts to upload that resulted in an error */\n error: t.string,\n /** The update body */\n update: PreferenceUpdateItem,\n }),\n);\n\n/** Override type */\nexport type FailingPreferenceUpdates = t.TypeOf<typeof FailingPreferenceUpdates>;\n\n/**\n * This is the type of the pending updates that are in conflict with existing consent preferences.\n *\n * Key is primaryKey of the record in the file.\n * The value is the row in the file that is pending upload.\n */\nexport const PendingWithConflictPreferenceUpdates = t.record(\n t.string,\n // We always return the conflicts for investigation\n t.type({\n /** Record to be inserted to transcend v1/preferences API */\n record: PreferenceQueryResponseItem,\n /** The row in the file that is pending upload */\n row: t.record(t.string, t.string),\n }),\n);\n\n/** Override type */\nexport type PendingWithConflictPreferenceUpdates = t.TypeOf<\n typeof PendingWithConflictPreferenceUpdates\n>;\n\n/**\n * The set of preference updates that are skipped\n * Key is primaryKey and value is the row in the CSV\n * that is skipped.\n *\n * This is usually because the preferences are already in the store\n * or there are duplicate rows in the CSV file that are identical.\n */\nexport const SkippedPreferenceUpdates = t.record(t.string, t.record(t.string, t.string));\n\n/** Override type */\nexport type SkippedPreferenceUpdates = t.TypeOf<typeof SkippedPreferenceUpdates>;\n\n/** Persist this data between runs of the script */\nexport const PreferenceState = t.type({\n /**\n * Store a cache of previous files read in\n */\n fileMetadata: t.record(t.string, FileMetadataState),\n /**\n * The set of successful uploads to Transcend\n * Mapping from userId to the upload metadata\n */\n failingUpdates: t.record(\n t.string,\n t.type({\n /** Time upload ran at */\n uploadedAt: t.string,\n /** Attempts to upload that resulted in an error */\n error: t.string,\n /** The update body */\n update: PreferenceUpdateItem,\n }),\n ),\n /**\n * The set of pending uploads to Transcend\n * Mapping from userId to the upload metadata\n */\n pendingUpdates: t.record(t.string, PreferenceUpdateItem),\n});\n\n/** Override type */\nexport type PreferenceState = t.TypeOf<typeof PreferenceState>;\n\nexport const RequestUploadReceipts = t.type({\n /** ISO 8601 timestamp of when the receipt file was last written */\n lastFetchedAt: t.string,\n /** Updates that can be applied without conflicting with existing preferences */\n pendingSafeUpdates: PendingSafePreferenceUpdates,\n /** Updates that conflict with existing preference values and need review */\n pendingConflictUpdates: PendingWithConflictPreferenceUpdates,\n /** Rows skipped because their preferences already match the store */\n skippedUpdates: SkippedPreferenceUpdates,\n /** Updates that were attempted but failed with an API error */\n failingUpdates: FailingPreferenceUpdates,\n /** Updates still queued to be sent to the API */\n pendingUpdates: PreferenceUpdateMap,\n /** Updates that have been successfully written to the preference store */\n successfulUpdates: PreferenceUpdateMap,\n});\n\n/** Override type */\nexport type RequestUploadReceipts = t.TypeOf<typeof RequestUploadReceipts>;\n\nexport const DeletePreferenceRecordsInput = t.type({\n /** Array of consent preference records to delete */\n records: t.array(\n t.type({\n /** The anchor identifier to locate the consent record */\n anchorIdentifier: PreferenceStoreIdentifier,\n /** The ISO 8601 timestamp of when the deletion is requested */\n timestamp: t.string,\n }),\n ),\n});\n\n/** Override type */\nexport type DeletePreferenceRecordsInput = t.TypeOf<typeof DeletePreferenceRecordsInput>;\n\nexport const DeletePreferenceRecordsResponse = t.intersection([\n t.type({\n /** Array of results for each preference record deletion */\n records: t.array(\n t.intersection([\n t.type({\n /** Whether the deletion was successful */\n success: t.boolean,\n }),\n t.partial({\n /** An error message if the deletion failed */\n errorMessage: t.string,\n }),\n ]),\n ),\n /** The list of failed deletions with their respective errors */\n failures: t.array(\n t.type({\n /** The index of the failed update in the original request */\n index: t.number,\n /** The error message associated with the failure */\n error: t.string,\n }),\n ),\n }),\n t.partial({\n /** Any general errors that occurred during the operation */\n errors: t.array(t.string),\n }),\n]);\n\n/** Override type */\nexport type DeletePreferenceRecordsResponse = t.TypeOf<typeof DeletePreferenceRecordsResponse>;\n\n/** CLI CSV Row for deleting preference records */\nexport const DeletePreferenceRecordCliCsvRow = t.type({\n /** The name of the identifier type (e.g., email, userId) */\n name: t.string,\n /** The value of the identifier */\n value: t.string,\n});\n\n/** Override type */\nexport type DeletePreferenceRecordCliCsvRow = t.TypeOf<typeof DeletePreferenceRecordCliCsvRow>;\n","import type { ColumnMetadataMap } from './codecs.js';\n\n/**\n * Extract metadata values from a CSV row based on the column-to-metadata mapping.\n *\n * @param options - Options for extracting metadata\n * @returns Array of metadata key-value pairs for the preference store API\n */\nexport function getPreferenceMetadataFromRow({\n row,\n columnToMetadata,\n}: {\n /** The CSV row as a record of column name to value */\n row: Record<string, string>;\n /** Mapping from CSV column name to metadata key */\n columnToMetadata: ColumnMetadataMap;\n}): Array<{\n /** Metadata key name */ key: string;\n /** Metadata value from the CSV row */\n value: string;\n}> {\n return Object.entries(columnToMetadata)\n .map(([columnName, { key }]) => {\n const value = row[columnName];\n // Skip if no value in the row or empty string\n if (value === undefined || value === '') {\n return null;\n }\n return { key, value };\n })\n .filter(\n (\n x,\n ): x is {\n /** Metadata key name */ key: string;\n /** Metadata value from the CSV row */\n value: string;\n } => x !== null,\n );\n}\n","import type { PreferenceStoreIdentifier } from '@transcend-io/privacy-types';\n\nimport type { FileFormatState } from './codecs.js';\n\n/**\n * Extract preference store identifiers from a CSV row based on the column-to-identifier mapping.\n *\n * @param options - Options\n * @returns Array of identifiers for the preference store API\n */\nexport function getPreferenceIdentifiersFromRow({\n row,\n columnToIdentifier,\n}: {\n /** The current row from CSV file */\n row: Record<string, string>;\n /** The current file metadata state */\n columnToIdentifier: FileFormatState['columnToIdentifier'];\n}): PreferenceStoreIdentifier[] {\n const identifiers = Object.entries(columnToIdentifier)\n .filter(([col]) => !!row[col])\n .map(([col, identifierMapping]) => ({\n name: identifierMapping.name,\n value: row[col]!,\n }));\n return identifiers.sort(\n (a, b) =>\n (a.name === 'email' ? -1 : 0) - (b.name === 'email' ? -1 : 0) ||\n a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }),\n );\n}\n","import type { FileFormatState, IdentifierMetadataForPreference } from './codecs.js';\n\n/**\n * Helper function to get unique identifier name present in a row\n *\n * @param options - Options\n * @param options.row - The current row from CSV file\n * @param options.columnToIdentifier - The column to identifier mapping metadata\n * @returns The unique identifier names present in the row\n */\nexport function getUniquePreferenceIdentifierNamesFromRow({\n row,\n columnToIdentifier,\n}: {\n /** The current row from CSV file */\n row: Record<string, string>;\n /** The current file metadata state */\n columnToIdentifier: FileFormatState['columnToIdentifier'];\n}): (IdentifierMetadataForPreference & {\n /** Column name */\n columnName: string;\n /** Value of the identifier in the row */\n value: string;\n})[] {\n return Object.entries(columnToIdentifier)\n .sort(\n ([, a], [, b]) =>\n (a.name === 'email' ? -1 : 0) - (b.name === 'email' ? -1 : 0) ||\n a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }),\n )\n .filter(([col]) => row[col] && columnToIdentifier[col]!.isUniqueOnPreferenceStore)\n .map(([col, identifier]) => ({\n ...identifier,\n columnName: col,\n value: row[col]!,\n }));\n}\n","import { PreferenceStorePurposeResponse, PreferenceTopicType } from '@transcend-io/privacy-types';\nimport { apply } from '@transcend-io/type-utils';\nimport { splitCsvToList } from '@transcend-io/utils';\n\nimport { PurposeRowMapping } from './codecs.js';\nimport type { PreferenceTopic } from './fetchAllPreferenceTopics.js';\n\n/**\n * Parse an arbitrary object to the Transcend PUT /v1/preference update shape\n * by using a mapping of column names to purpose/preference slugs.\n *\n * `columnToPurposeName` looks like:\n * {\n * 'my_purpose': { purpose: 'Marketing', preference: null, valueMapping: { 'true': true, 'false': false } },\n * 'has_topic_1': { purpose: 'Marketing', preference: 'BooleanPreference1', valueMapping: { 'true': true, 'false': false } },\n * 'has_topic_2': { purpose: 'Marketing', preference: 'SingleSelectPreference', valueMapping: { 'Option 1': 'Value1', 'Option 2': 'Value2' } }\n * }\n *\n * `row` looks like:\n * {\n * 'my_purpose': 'true',\n * 'has_topic_1': 'true',\n * 'has_topic_2': 'Option 1'\n * }\n *\n * OMISSION RULE:\n * - If `valueMapping[row[columnName]]`\n * returns `undefined` or `null`, we **omit** that column entirely (do not set purpose enabled, do not push a preference).\n * - For MultiSelect, **each token** is treated independently: tokens that map to `undefined|null` are skipped;\n * if all tokens are skipped, nothing is pushed.\n * - We still validate **types** for mapped values (e.g., boolean must map to boolean, select must map to string, etc.).\n *\n * NOTE:\n * - Final shape must have `enabled` for every purpose touched (enforced by `apply` below). If you omit all top-level purpose mappings,\n * but emit preferences, this will throw at the end. This preserves the existing “enabled required” contract.\n *\n * @param options - Options\n * @returns The parsed row\n */\nexport function getPreferenceUpdatesFromRow({\n row,\n columnToPurposeName,\n purposeSlugs,\n preferenceTopics,\n}: {\n /** Row to parse */\n row: Record<string, string>;\n /** Mapping from column name to parser config */\n columnToPurposeName: Record<string, PurposeRowMapping>;\n /** The set of allowed purpose slugs */\n purposeSlugs: string[];\n /** The preference topics */\n preferenceTopics: PreferenceTopic[];\n}): {\n [k in string]: Omit<PreferenceStorePurposeResponse, 'purpose'>;\n} {\n // Create a result object to store the parsed preferences\n const result: {\n [k in string]: Partial<PreferenceStorePurposeResponse>;\n } = {};\n\n // Iterate over each column and map to the purpose or preference\n Object.entries(columnToPurposeName).forEach(\n ([columnName, { purpose, preference, valueMapping }]) => {\n // Ensure the purpose is valid\n if (!purposeSlugs.includes(purpose)) {\n throw new Error(`Invalid purpose slug: ${purpose}, expected: ${purposeSlugs.join(', ')}`);\n }\n\n // The raw value from the CSV row for this column\n const rawValue = row[columnName] ?? '';\n\n // Check if parsing a preference or just the top level purpose\n if (preference) {\n const preferenceTopic = preferenceTopics.find(\n (x) => x.slug === preference && x.purpose.trackingType === purpose,\n );\n if (!preferenceTopic) {\n const allowedTopics = preferenceTopics\n .filter((x) => x.purpose.trackingType === purpose)\n .map((x) => x.slug);\n throw new Error(\n `Invalid preference slug: ${preference} for purpose: ${purpose}. ` +\n `Allowed preference slugs for purpose are: ${allowedTopics.join(',')}`,\n );\n }\n\n // Ensure destination array\n if (!result[purpose]) {\n result[purpose] = {\n preferences: [],\n };\n }\n if (!result[purpose].preferences) {\n result[purpose].preferences = [];\n }\n\n // handle each type of preference\n switch (preferenceTopic.type) {\n case PreferenceTopicType.Boolean: {\n const mappedValue = valueMapping[rawValue];\n // Throw error on missing mapping\n if (mappedValue === undefined && rawValue !== '') {\n throw new Error(\n `No preference mapping found for value \"${rawValue}\" in column ` +\n `\"${columnName}\" (purpose=${purpose}, preference=${preference})`,\n );\n }\n\n // Purposefully missing mapping\n if (mappedValue === null || mappedValue === undefined) {\n return;\n }\n\n // Ensure boolean\n if (typeof mappedValue !== 'boolean') {\n throw new Error(\n `Invalid value for boolean preference: ${preference}, expected boolean, got: ${rawValue}`,\n );\n }\n result[purpose].preferences!.push({\n topic: preference,\n choice: { booleanValue: mappedValue },\n });\n break;\n }\n\n case PreferenceTopicType.Select: {\n const mappedValue = valueMapping[rawValue];\n // Throw error on missing mapping\n if (mappedValue === undefined && rawValue !== '') {\n throw new Error(\n `No preference mapping found for value \"${rawValue}\" in column ` +\n `\"${columnName}\" (purpose=${purpose}, preference=${preference})`,\n );\n }\n\n // Omit if null\n if (mappedValue === null || mappedValue === undefined) {\n return;\n }\n\n // Ensure string\n if (typeof mappedValue !== 'string') {\n throw new Error(\n `Invalid value for select preference: ${preference}, expected string, got: ${rawValue}`,\n );\n }\n const trimmed = mappedValue.trim() || null;\n\n if (\n trimmed &&\n !preferenceTopic.preferenceOptionValues.map(({ slug }) => slug).includes(trimmed)\n ) {\n throw new Error(\n `Invalid value for select preference: ${preference}, expected one of: ` +\n `${preferenceTopic.preferenceOptionValues\n .map(({ slug }) => slug)\n .join(', ')}, got: ${rawValue}`,\n );\n }\n\n result[purpose].preferences!.push({\n topic: preference,\n choice: { selectValue: trimmed },\n });\n break;\n }\n\n case PreferenceTopicType.MultiSelect: {\n if (typeof rawValue !== 'string') {\n throw new Error(\n `Invalid value for multi select preference: ${preference}, expected string, got: ${rawValue}`,\n );\n }\n\n // IMPORTANT: Do NOT rely on valueMapping[rawValue] for CSV.\n // Split and map per token with the new rule.\n const selectValues = splitCsvToList(rawValue)\n .map((token) => {\n const tokenMapped = valueMapping[token];\n // Throw error on missing mapping\n if (tokenMapped === undefined && rawValue !== '') {\n throw new Error(\n `No preference mapping found for multi select token \"${rawValue}\" in column ` +\n `\"${columnName}\" (purpose=${purpose}, preference=${preference})`,\n );\n }\n\n // Omit if null\n if (tokenMapped === null || tokenMapped === undefined) {\n return null;\n }\n\n // Ensure string\n if (typeof tokenMapped !== 'string') {\n throw new Error(\n `Invalid value for multi select preference: ${preference}, ` +\n `expected one of: ${preferenceTopic.preferenceOptionValues\n .map(({ slug }) => slug)\n .join(', ')}, got: ${token}`,\n );\n }\n return tokenMapped;\n })\n .filter((x): x is string => x !== null)\n .sort((a, b) => a.localeCompare(b));\n\n // Only push if at least one mapped token survived\n if (selectValues.length > 0) {\n result[purpose].preferences!.push({\n topic: preference,\n choice: { selectValues },\n });\n }\n break;\n }\n\n default:\n throw new Error(`Unknown preference type: ${preferenceTopic.type}`);\n }\n } else {\n // Top-level purpose (no preference)\n const mappedValue = valueMapping[rawValue];\n if (mappedValue === undefined && rawValue !== '') {\n throw new Error(\n `No preference mapping found for value \"${rawValue}\" in column ` +\n `\"${columnName}\" (purpose=${purpose}, preference=∅) ${JSON.stringify(row)}`,\n );\n }\n if (mappedValue === null) {\n return; // Omit if null\n }\n\n if (!result[purpose]) {\n // Top-level purpose: set enabled strictly from mapped boolean\n result[purpose] = { enabled: mappedValue === true };\n } else {\n // Preserve preferences; update enabled\n result[purpose].enabled = mappedValue === true;\n }\n }\n },\n );\n\n // Ensure that enabled is provided for any purpose that appears.\n // (This preserves the prior contract and existing tests.)\n return apply(result, (x, purposeName) => {\n if (typeof x.enabled !== 'boolean') {\n throw new Error(`No mapping provided for purpose.enabled=true/false value: ${purposeName}`);\n }\n return {\n ...x,\n enabled: x.enabled!,\n };\n });\n}\n","import {\n PreferenceQueryResponseItem,\n PreferenceStorePurposeResponse,\n PreferenceTopicType,\n} from '@transcend-io/privacy-types';\n\nimport type { PreferenceTopic } from './fetchAllPreferenceTopics.js';\n\n/**\n * Check if the pending set of updates are exactly the same as the current consent record.\n *\n * @param options - Options\n * @returns Whether the pending updates already exist in the preference store\n */\nexport function checkIfPendingPreferenceUpdatesAreNoOp({\n currentConsentRecord,\n pendingUpdates,\n preferenceTopics,\n}: {\n /** The current consent record */\n currentConsentRecord: PreferenceQueryResponseItem;\n /** The pending updates */\n pendingUpdates: {\n [purposeName in string]: Omit<PreferenceStorePurposeResponse, 'purpose'>;\n };\n /** The preference topic configurations */\n preferenceTopics: PreferenceTopic[];\n}): boolean {\n // Check each update\n return Object.entries(pendingUpdates).every(([purposeName, { preferences = [], enabled }]) => {\n // Ensure the purpose exists\n const currentPurpose = currentConsentRecord.purposes.find(\n (existingPurpose) => existingPurpose.purpose === purposeName,\n );\n\n // Ensure purpose.enabled is in sync\n // Also false if the purpose does not exist\n const enabledIsInSync = !!currentPurpose && currentPurpose.enabled === enabled;\n if (!enabledIsInSync) {\n return false;\n }\n\n // Compare the preferences are in sync\n return preferences.every(\n ({ topic, choice }) =>\n // ensure preferences exist on record\n currentPurpose.preferences &&\n currentPurpose.preferences.find((existingPreference) => {\n // find matching topic\n if (existingPreference.topic !== topic) {\n return false;\n }\n\n // Determine type of preference topic\n const preferenceTopic = preferenceTopics.find(\n (x) => x.slug === topic && x.purpose.trackingType === purposeName,\n );\n if (!preferenceTopic) {\n throw new Error(`Could not find preference topic for ${topic}`);\n }\n\n // Handle comparison based on type\n switch (preferenceTopic.type) {\n case PreferenceTopicType.Boolean:\n return existingPreference.choice.booleanValue === choice.booleanValue;\n case PreferenceTopicType.Select:\n return existingPreference.choice.selectValue === choice.selectValue;\n case PreferenceTopicType.MultiSelect:\n // eslint-disable-next-line no-case-declarations\n const sortedCurrentValues = (existingPreference.choice.selectValues || []).sort();\n // eslint-disable-next-line no-case-declarations\n const sortedNewValues = (choice.selectValues || []).sort();\n return (\n sortedCurrentValues.length === sortedNewValues.length &&\n sortedCurrentValues.every((x, i) => x === sortedNewValues[i])\n );\n default:\n throw new Error(`Unknown preference topic type: ${preferenceTopic.type}`);\n }\n }),\n );\n });\n}\n","import {\n PreferenceQueryResponseItem,\n PreferenceStorePurposeResponse,\n PreferenceTopicType,\n} from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\n\nimport type { PreferenceTopic } from './fetchAllPreferenceTopics.js';\n\n/**\n * Check if the pending set of updates will result in a change of\n * value to an existing purpose or preference in the preference store.\n *\n * @param options - Options\n * @returns True if conflict, false if no conflict and just adding new data for first time\n */\nexport function checkIfPendingPreferenceUpdatesCauseConflict({\n currentConsentRecord,\n pendingUpdates,\n preferenceTopics,\n logger,\n}: {\n /** The current consent record */\n currentConsentRecord: PreferenceQueryResponseItem;\n /** The pending updates */\n pendingUpdates: {\n [purposeName in string]: Omit<PreferenceStorePurposeResponse, 'purpose'>;\n };\n /** The preference topic configurations */\n preferenceTopics: PreferenceTopic[];\n /** Optional logger — when provided, conflicts are logged */\n logger?: Logger;\n}): boolean {\n // Check if any update has conflict\n return !!Object.entries(pendingUpdates).find(([purposeName, { preferences = [], enabled }]) => {\n // Ensure the purpose exists\n const currentPurpose = currentConsentRecord.purposes.find(\n (existingPurpose) => existingPurpose.purpose === purposeName,\n );\n\n // If no purpose exists, then it is not a conflict\n if (!currentPurpose) {\n logger?.warn(\n `No existing purpose found for ${purposeName} in consent record for ${currentConsentRecord.userId}.`,\n );\n return false;\n }\n\n // If purpose.enabled value is off, this is a conflict\n if (currentPurpose.enabled !== enabled) {\n logger?.warn(\n `Purpose ${purposeName} enabled value conflict for user ${currentConsentRecord.userId}. ` +\n `Pending Value: ${enabled}, Current Value: ${currentPurpose.enabled}`,\n );\n return true;\n }\n\n // Check if any preferences are out of sync\n return !!preferences.find(({ topic, choice }) => {\n // find matching topic\n const currentPreference = (currentPurpose.preferences || []).find(\n (existingPreference) => existingPreference.topic === topic,\n );\n\n // if no topic exists, no conflict\n if (!currentPreference) {\n logger?.warn(\n `No existing preference found for topic ${topic} in purpose ` +\n `${purposeName} for user ${currentConsentRecord.userId}.`,\n );\n return false;\n }\n\n // Determine type of preference topic\n const preferenceTopic = preferenceTopics.find(\n (x) => x.slug === topic && x.purpose.trackingType === purposeName,\n );\n if (!preferenceTopic) {\n throw new Error(`Could not find preference topic for ${topic}`);\n }\n\n // Handle comparison based on type\n let boolMatch: boolean;\n let selectMatch: boolean;\n switch (preferenceTopic.type) {\n case PreferenceTopicType.Boolean:\n boolMatch = currentPreference.choice.booleanValue !== choice.booleanValue;\n logger?.warn(\n `Preference topic ${topic} boolean value conflict for user ` +\n `${currentConsentRecord.userId}. Expected: ${choice.booleanValue}, ` +\n `Found: ${currentPreference.choice.booleanValue}`,\n );\n return boolMatch;\n case PreferenceTopicType.Select:\n selectMatch = currentPreference.choice.selectValue !== choice.selectValue;\n logger?.warn(\n `Preference topic ${topic} select value conflict for user ` +\n `${currentConsentRecord.userId}. Expected: ${choice.selectValue}, ` +\n `Found: ${currentPreference.choice.selectValue}`,\n );\n return selectMatch;\n case PreferenceTopicType.MultiSelect:\n // eslint-disable-next-line no-case-declarations\n const sortedCurrentValues = (currentPreference.choice.selectValues || []).sort();\n // eslint-disable-next-line no-case-declarations\n const sortedNewValues = (choice.selectValues || []).sort();\n selectMatch =\n sortedCurrentValues.length !== sortedNewValues.length ||\n !sortedCurrentValues.every((x, i) => x === sortedNewValues[i]);\n logger?.warn(\n `Preference topic ${topic} multi-select value conflict for user ` +\n `${currentConsentRecord.userId}. Expected: ${sortedNewValues.join(\n ', ',\n )}, Found: ${sortedCurrentValues.join(', ')}`,\n );\n return selectMatch;\n default:\n throw new Error(`Unknown preference topic type: ${preferenceTopic.type}`);\n }\n });\n });\n}\n","import { extractErrorMessage, sleepPromise, type Logger } from '@transcend-io/utils';\n\nimport { NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\n\n/**\n * Transient network / platform errors that merit a retry.\n * Keep this list short and specific to avoid masking real failures.\n */\nexport const RETRY_PREFERENCE_MSGS: string[] = [\n 'ENOTFOUND',\n 'ECONNRESET',\n 'ETIMEDOUT',\n '502 Bad Gateway',\n '504 Gateway Time-out',\n '429',\n 'Rate limit exceeded',\n 'Task timed out after',\n 'unknown request error',\n].map((s) => s.toLowerCase());\n\n/**\n * Options for retrying preference operations.\n */\nexport type RetryOptions = {\n logger?: Logger;\n /** Max attempts including the first try (default 12) */\n maxAttempts?: number;\n /** Initial backoff in ms (default 250) */\n baseDelayMs?: number;\n /** Optional custom predicate to decide if an error is retryable */\n isRetryable?: (err: unknown, message: string) => boolean;\n /** Optional hook to log on each retry */\n onRetry?: (attempt: number, err: unknown, message: string) => void;\n};\n\n/**\n * Run an async function with standardized retry behavior for preference operations.\n * Exponential backoff with jitter; only retries on known-transient messages.\n *\n * @param name - Name of the operation (for logging)\n * @param fn - Function to run\n * @param options - Retry options\n * @returns Result of the function\n */\nexport async function withPreferenceRetry<T>(\n name: string,\n fn: () => Promise<T>,\n {\n logger = NOOP_LOGGER,\n maxAttempts = 12,\n baseDelayMs = 250,\n isRetryable = (_err, msg) => RETRY_PREFERENCE_MSGS.some((m) => msg.toLowerCase().includes(m)),\n onRetry,\n }: RetryOptions,\n): Promise<T> {\n let attempt = 0;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n attempt += 1;\n try {\n return await fn();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (err: any) {\n const msg: string = extractErrorMessage(err);\n const willRetry = attempt < maxAttempts && isRetryable(err, msg);\n if (!willRetry) {\n throw new Error(`${name} failed after ${attempt} attempt(s): ${msg}`);\n }\n onRetry?.(attempt, err, msg);\n\n const backoff = baseDelayMs * 2 ** (attempt - 1);\n const jitter = Math.floor(Math.random() * baseDelayMs);\n const delay = backoff + jitter;\n logger.warn(`[retry] attempt ${attempt}/${maxAttempts - 1}; backing off ${delay}ms: ${msg}`);\n await sleepPromise(delay);\n }\n }\n}\n","import type { PreferenceQueryResponseItem } from '@transcend-io/privacy-types';\n\n/**\n * Transforms the output of the consent preferences query into a CSV-friendly format.\n *\n * @param input - The input object containing consent preferences data.\n * @param exportIdentifiersWithDelimiter - Delimiter to use when combining multiple identifier values.\n * @returns A record representing the transformed CSV output.\n */\nexport function transformPreferenceRecordToCsv(\n {\n identifiers = [],\n purposes = [],\n metadata = [],\n consentManagement = {},\n system = {\n decryptionStatus: 'DECRYPTED',\n },\n // keep other top-level fields as-is (e.g., partition, timestamp, metadataTimestamp)\n ...topLevel\n }: PreferenceQueryResponseItem,\n exportIdentifiersWithDelimiter: string,\n): Record<string, unknown> {\n // Start with: all other top-level fields + spread system and consentManagement\n const out: Record<string, unknown> = {\n ...topLevel,\n ...system,\n ...consentManagement,\n };\n\n // ── identifiers: each identifier.name -> CSV of values\n if (Array.isArray(identifiers)) {\n const byName = new Map<string, Set<string>>();\n for (const { name, value } of identifiers) {\n if (!byName.has(name)) byName.set(name, new Set());\n if (value) byName.get(name)!.add(value);\n }\n for (const [name, set] of byName.entries()) {\n out[name] = Array.from(set).join(exportIdentifiersWithDelimiter);\n }\n }\n\n // ── metadata: serialize as JSON\n if (Array.isArray(metadata)) {\n out.metadata = JSON.stringify(\n metadata.reduce(\n (acc, { key, value }) => {\n acc[key] = value;\n return acc;\n },\n {} as Record<string, string>,\n ),\n );\n }\n\n // ── purposes:\n // - purpose.slug column => true/false (enabled)\n // - for each preference: purpose.slug_preference.slug => bool | single | CSV (multi)\n if (Array.isArray(purposes)) {\n for (const { purpose, preferences, enabled } of purposes) {\n out[purpose] = Boolean(enabled);\n\n // nested preferences\n if (Array.isArray(preferences)) {\n for (const { topic, choice } of preferences) {\n const col = `${purpose}_${topic}`;\n\n let val: unknown = null;\n\n if (typeof choice.booleanValue === 'boolean') {\n val = choice.booleanValue;\n } else if (choice.selectValue) {\n val = choice.selectValue;\n } else if (Array.isArray(choice.selectValues)) {\n const vs = choice.selectValues.filter((v) => v.length > 0);\n val = vs.join(',');\n } else {\n // no pref value present -> null\n val = null;\n }\n\n out[col] = val;\n }\n }\n }\n }\n\n return out;\n}\n","import { FIVE_MIN_MS } from '@transcend-io/utils';\n\nimport type { ChunkMode, PreferencesQueryFilter } from './types.js';\n\n/**\n * Build chunk windows by splitting [lower, upperExclusive) into up to `maxChunks`\n * equal-sized ranges, with a minimum chunk span of 5 minutes. Boundaries are snapped\n * once at the start to the nearest 5-minute boundary for stability.\n *\n * Each returned window is already \"half-open\" for an *inclusive* backend:\n * we subtract 1ms from the exclusive end so adjacent chunks do not overlap.\n *\n * Example (timestamp mode): [10:00, 12:00) → { after=10:00:00.000Z, before=11:59:59.999Z }\n *\n * @param mode - 'timestamp' or 'updated'\n * @param lower - Lower bound (inclusive)\n * @param upperExclusive - Upper bound (exclusive)\n * @param maxChunks - Maximum number of chunks to create\n * @returns Array of chunked preference query filters\n */\nexport function buildConsentChunks(\n mode: ChunkMode,\n lower: Date,\n upperExclusive: Date,\n maxChunks = 5000,\n): Array<PreferencesQueryFilter> {\n const totalMs = Math.max(0, upperExclusive.getTime() - lower.getTime());\n if (totalMs === 0) return [];\n\n // Snap only the starting boundary to the nearest 5-minute boundary.\n // We avoid re-snapping every step to prevent cumulative drift.\n const seriesStart = new Date(Math.floor(lower.getTime() / FIVE_MIN_MS) * FIVE_MIN_MS);\n\n // Compute base chunk size (ceil to ensure ≤ maxChunks), enforced ≥ 5m.\n const rawChunkMs = Math.ceil(totalMs / Math.max(1, maxChunks));\n const chunkMs = Math.max(FIVE_MIN_MS, rawChunkMs);\n\n // Number of chunks needed to cover [seriesStart, upperExclusive)\n const count = Math.ceil((upperExclusive.getTime() - seriesStart.getTime()) / chunkMs);\n\n const chunks: PreferencesQueryFilter[] = [];\n\n for (let i = 0; i < count; i += 1) {\n const startMs = seriesStart.getTime() + i * chunkMs;\n const endExclusiveMs = Math.min(upperExclusive.getTime(), startMs + chunkMs);\n\n // Convert exclusive end to inclusive end for an inclusive backend: -1ms.\n const endInclusiveMs = endExclusiveMs - 1;\n\n // Guard: in degenerate cases (shouldn’t happen with the math above), clamp.\n const safeEndMs = Math.max(startMs, endInclusiveMs);\n\n const afterIso = new Date(startMs).toISOString();\n const beforeIso = new Date(safeEndMs).toISOString();\n\n if (mode === 'timestamp') {\n chunks.push({\n timestampAfter: afterIso,\n timestampBefore: beforeIso,\n });\n } else {\n chunks.push({\n system: {\n updatedAfter: afterIso,\n updatedBefore: beforeIso,\n },\n });\n }\n }\n\n return chunks;\n}\n","import type { ChunkMode, PreferencesQueryFilter } from './types.js';\n\n/**\n * Decide which dimension to chunk on: 'timestamp' if timestamps provided, otherwise 'updated'\n *\n * @param filterBy - Filter to examine\n * @returns Chosen chunk mode\n */\nexport function pickConsentChunkMode(filterBy: PreferencesQueryFilter): ChunkMode {\n const hasTimestamp = !!filterBy.timestampAfter || !!filterBy.timestampBefore;\n return hasTimestamp ? 'timestamp' : 'updated';\n}\n","import type { PreferenceQueryResponseItem } from '@transcend-io/privacy-types';\n\nimport type { ChunkMode } from './types.js';\n\n/**\n * Get the comparison instant for sorting based on the chosen dimension.\n *\n * @param mode - Chunking mode\n * @param item - Preference item\n * @returns date\n */\nexport function getComparisonTimeForRecord(\n mode: ChunkMode,\n item: PreferenceQueryResponseItem,\n): Date {\n if (mode === 'timestamp') {\n return new Date(item.timestamp);\n }\n // mode === 'updated'\n return item.system?.updatedAt ? new Date(item.system.updatedAt) : new Date();\n}\n","import type { PreferenceQueryResponseItem } from '@transcend-io/privacy-types';\nimport { decodeCodec } from '@transcend-io/type-utils';\nimport type { Logger } from '@transcend-io/utils';\nimport type { Got } from 'got';\n\nimport { ConsentPreferenceResponse, type PreferencesQueryFilter } from './types.js';\nimport { withPreferenceRetry } from './withPreferenceRetry.js';\n\n/**\n * Async generator over pages for a given filter\n *\n * @param sombra - Sombra Got instance\n * @param partition - Partition key\n * @param filter - Query filter\n * @param pageSize - Number of items per page\n * @param logger - Logger for retries\n * @yields Pages of PreferenceQueryResponseItem\n */\nexport async function* iterateConsentPages(\n sombra: Got,\n partition: string,\n filter: PreferencesQueryFilter,\n pageSize: number,\n logger: Logger,\n): AsyncGenerator<PreferenceQueryResponseItem[], void, void> {\n let cursor: string | undefined;\n\n while (true) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const body: any = { limit: pageSize };\n if (filter && Object.keys(filter).length) body.filter = filter;\n if (cursor) body.cursor = cursor;\n\n const resp = await withPreferenceRetry(\n 'Preference Query',\n () =>\n sombra\n .post(`v1/preferences/${partition}/query`, {\n json: body,\n })\n .json(),\n {\n logger,\n onRetry: (attempt, _error, message) => {\n logger.warn(`Retry attempt ${attempt} for iterateConsentPages due to error: ${message}`);\n },\n },\n );\n\n const { nodes, cursor: nextCursor } = decodeCodec(ConsentPreferenceResponse, resp);\n if (!nodes?.length) break;\n\n yield nodes;\n\n if (!nextCursor) break;\n cursor = nextCursor;\n }\n}\n","import { decodeCodec } from '@transcend-io/type-utils';\nimport type { Logger } from '@transcend-io/utils';\nimport type { Got } from 'got';\n\nimport { NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { ConsentPreferenceResponse, type PreferencesQueryFilter, type ChunkMode } from './types.js';\nimport { withPreferenceRetry } from './withPreferenceRetry.js';\n\n/**\n * Probe window: does it contain any records? Uses the given mode.\n *\n * @param sombra - Sombra\n * @param options - Options\n * @returns True if any records exist in the given window\n */\nexport async function consentWindowHasAny(\n sombra: Got,\n {\n partition,\n mode,\n baseFilter,\n afterISO,\n beforeISO,\n logger = NOOP_LOGGER,\n }: {\n /** Partition */\n partition: string;\n /** Chunking mode */\n mode: ChunkMode;\n /** Base filter */\n baseFilter: PreferencesQueryFilter;\n /** After ISO date */\n afterISO: string;\n /** Before ISO date */\n beforeISO: string;\n logger?: Logger;\n },\n): Promise<boolean> {\n const filter: PreferencesQueryFilter =\n mode === 'timestamp'\n ? {\n ...baseFilter,\n timestampAfter: afterISO,\n timestampBefore: beforeISO,\n system: baseFilter.system,\n }\n : {\n ...baseFilter,\n timestampAfter: undefined,\n timestampBefore: undefined,\n system: {\n ...baseFilter.system,\n updatedAfter: afterISO,\n updatedBefore: beforeISO,\n },\n };\n const resp = await withPreferenceRetry(\n 'Preference Query',\n () =>\n sombra\n .post(`v1/preferences/${partition}/query`, {\n json: { limit: 1, filter },\n })\n .json(),\n {\n logger,\n onRetry: (attempt, error, message) => {\n logger.warn(`Retry attempt ${attempt} for consentWindowHasAny due to error: ${message}`);\n },\n },\n );\n\n const { nodes } = decodeCodec(ConsentPreferenceResponse, resp);\n return Array.isArray(nodes) && nodes.length > 0;\n}\n","import type { PreferenceQueryResponseItem } from '@transcend-io/privacy-types';\nimport { startOfUtcDay, DAY_MS, type Logger } from '@transcend-io/utils';\n/* eslint-disable max-lines */\nimport type { Got } from 'got';\n\nimport { NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { getComparisonTimeForRecord } from './getComparisonTimeForRecord.js';\nimport { iterateConsentPages } from './iterateConsentPages.js';\nimport { pickConsentChunkMode } from './pickConsentChunkMode.js';\nimport { type ChunkMode, type PreferencesQueryFilter } from './types.js';\n\n/**\n * Get after/before bounds from filter for the given mode\n *\n * @param mode - Chunking mode\n * @param filterBy - Filter to examine\n * @returns after/before dates\n */\nexport function getBoundsFromConsentFilter(\n mode: ChunkMode,\n filterBy: PreferencesQueryFilter,\n): {\n /** After date */\n after?: Date;\n /** Before date */\n before?: Date;\n} {\n if (mode === 'timestamp') {\n return {\n after: filterBy.timestampAfter ? new Date(filterBy.timestampAfter) : undefined,\n before: filterBy.timestampBefore ? new Date(filterBy.timestampBefore) : undefined,\n };\n }\n const u = filterBy.system ?? {};\n return {\n after: u.updatedAfter ? new Date(u.updatedAfter) : undefined,\n before: u.updatedBefore ? new Date(u.updatedBefore) : undefined,\n };\n}\n\n/**\n * Merge base filter with a \"before\" bound (without mixing dimensions).\n *\n * @param mode - Chunking mode\n * @param base - Base filter to augment\n * @param beforeISO - ISO timestamp to apply as the exclusive *Before bound for the chosen dimension\n * @returns New filter with the appropriate *Before constraint applied\n */\nfunction withBeforeBound(\n mode: ChunkMode,\n base: PreferencesQueryFilter,\n beforeISO?: string,\n): PreferencesQueryFilter {\n if (mode === 'timestamp') {\n return {\n ...base,\n timestampBefore: beforeISO ?? base.timestampBefore,\n };\n }\n return {\n ...base,\n system: {\n ...base.system,\n ...(beforeISO ? { updatedBefore: beforeISO } : {}),\n },\n // ensure we don't mix dimensions\n timestampAfter: undefined,\n timestampBefore: undefined,\n };\n}\n\n/**\n * Fetch a single record (or null) with the given filter.\n *\n * @param sombra - Got instance configured for Sombra API\n * @param partition - Preference Store partition id\n * @param filter - Query filter to use (page size internally forced to 1)\n * @param logger - Logger\n * @returns The first record or null if none\n */\nasync function fetchOne(\n sombra: Got,\n partition: string,\n filter: PreferencesQueryFilter,\n logger: Logger,\n): Promise<PreferenceQueryResponseItem | null> {\n logger.info(`Single-record probe with filter: ${JSON.stringify(filter)}`);\n const it = iterateConsentPages(sombra, partition, filter, /* pageSize */ 1, logger);\n const res = await it.next();\n if (res.done || !res.value || res.value.length === 0) {\n logger.info('Probe result: no record');\n return null;\n }\n const item = res.value[0]!;\n logger.info(\n `Probe result: found record at ${getComparisonTimeForRecord(\n pickConsentChunkMode(filter),\n item,\n ).toISOString()}`,\n );\n return item;\n}\n\n/**\n * Robust earliest-day search (UTC):\n * 1) Anchor at the newest record (single-record probe).\n * 2) Exponential “jump back” using seeds (1d, 7d, 30d) then doubling (60d, 120d, 240d, …)\n * to cross into an empty region and establish a lower empty bound.\n * 3) **Exponential forward-from-empty**: gallop forward from the empty bound toward the last-found\n * to land close to the frontier quickly.\n * 4) Tighten with a short binary search on time using single-record probes.\n *\n * (Implementation note: preserves the public signature and docs while improving efficiency.)\n *\n * @param sombra - Sombra\n * @param opts - Options\n * @returns Earliest day with data (UTC start-of-day)\n */\nexport async function findEarliestDayWithData(\n sombra: Got,\n opts: {\n /** Partition */\n partition: string;\n /** Chunking mode */\n mode: ChunkMode;\n /** Base filter */\n baseFilter: PreferencesQueryFilter;\n /** Optional safety cap in days to avoid unbounded lookback (default ~10 years) */\n maxLookbackDays?: number;\n /** Logger */\n logger?: Logger;\n },\n): Promise<Date> {\n const { partition, mode, baseFilter, maxLookbackDays = 3650, logger = NOOP_LOGGER } = opts;\n\n // 1) Find newest record (anchors our backtracking).\n const newest = await fetchOne(sombra, partition, withBeforeBound(mode, baseFilter), logger);\n if (!newest) {\n logger.info('No records found; defaulting earliest day to today.');\n return startOfUtcDay(new Date());\n }\n const newestInstant = getComparisonTimeForRecord(mode, newest);\n logger.info(`Newest instant: ${newestInstant.toISOString()}`);\n\n // 2) Exponential jump back to find an empty region.\n const seedSteps = [1, 7, 30] as const; // days\n let stepDaysIdx = 0;\n let stepMs = seedSteps[0]! * DAY_MS;\n\n let lastFoundInstant = newestInstant; // last instant we *could* find a record before\n let emptyBeforeInstant: Date | null = null; // first bound that yielded no results\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const probeBound =\n stepDaysIdx < seedSteps.length\n ? new Date(newestInstant.getTime() - seedSteps[stepDaysIdx]! * DAY_MS)\n : new Date(newestInstant.getTime() - stepMs);\n\n // stop if we exceeded lookback cap\n const daysSince =\n (startOfUtcDay(new Date()).getTime() - startOfUtcDay(probeBound).getTime()) / DAY_MS;\n if (daysSince > maxLookbackDays) {\n logger.warn(\n `Exponential jump exceeded maxLookbackDays=${maxLookbackDays}. Using current bounds.`,\n );\n emptyBeforeInstant = probeBound;\n break;\n }\n\n logger.info(\n `Probing before=${probeBound.toISOString()} (jump step ${\n stepDaysIdx < seedSteps.length\n ? `${seedSteps[stepDaysIdx]!}d`\n : `${Math.round(stepMs / DAY_MS)}d`\n })…`,\n );\n\n const hit = await fetchOne(\n sombra,\n partition,\n withBeforeBound(mode, baseFilter, probeBound.toISOString()),\n logger,\n );\n\n if (hit) {\n lastFoundInstant = getComparisonTimeForRecord(mode, hit);\n logger.info(\n `Found older record at ${lastFoundInstant.toISOString()} — continue jumping back.`,\n );\n // advance step\n if (stepDaysIdx < seedSteps.length - 1) {\n stepDaysIdx += 1;\n stepMs = seedSteps[stepDaysIdx]! * DAY_MS;\n } else if (stepDaysIdx === seedSteps.length - 1) {\n stepDaysIdx += 1; // switch to doubling mode\n stepMs = seedSteps[seedSteps.length - 1]! * 2 * DAY_MS; // start at 60d\n } else {\n stepMs *= 2;\n }\n // eslint-disable-next-line no-continue\n continue;\n }\n\n // crossed into an empty zone — remember this bound\n emptyBeforeInstant = probeBound;\n logger.info(`No record before ${probeBound.toISOString()} — established empty lower bound.`);\n break;\n }\n\n // Guard: if for some reason empty bound wasn't set, synthesize one “just before” lastFound.\n if (!emptyBeforeInstant) {\n emptyBeforeInstant = new Date(lastFoundInstant.getTime() - DAY_MS);\n }\n\n // 3) Exponential forward-from-empty toward the found frontier.\n // This “gallop” reduces the span dramatically before binary search.\n // We keep moving the empty bound forward with exponentially growing steps\n // until we get a hit; then we shrink onto that hit instant.\n let lo = emptyBeforeInstant; // known EMPTY (no data before this bound)\n let hi = lastFoundInstant; // known FOUND (there is data before this instant)\n let fwdStep = Math.max(DAY_MS, Math.floor((hi.getTime() - lo.getTime()) / 64)); // start small-ish\n logger.info(\n `Exponential forward-from-empty start: empty=${lo.toISOString()} found=${hi.toISOString()} step=${Math.round(\n fwdStep / DAY_MS,\n )}d`,\n );\n\n // Do a few gallop iterations (bounded so we don't loop forever if distribution is dense)\n for (let i = 0; i < 8; i += 1) {\n const probe = new Date(lo.getTime() + fwdStep);\n if (probe.getTime() >= hi.getTime()) break;\n\n logger.info(`Forward gallop probe before=${probe.toISOString()}…`);\n const hit = await fetchOne(\n sombra,\n partition,\n withBeforeBound(mode, baseFilter, probe.toISOString()),\n logger,\n );\n\n if (hit) {\n // We crossed into data — tighten hi to the actual hit instant.\n hi = getComparisonTimeForRecord(mode, hit);\n logger.info(`Gallop hit at ${hi.toISOString()} — tightening found bound. Next step halves.`);\n fwdStep = Math.max(DAY_MS, Math.floor(fwdStep / 2));\n } else {\n // Still empty up to probe — advance lo and double the step.\n lo.setTime(probe.getTime());\n logger.info(`Gallop miss — advancing empty bound to ${lo.toISOString()}. Next step doubles.`);\n fwdStep = Math.min(hi.getTime() - lo.getTime(), fwdStep * 2);\n if (fwdStep < DAY_MS) fwdStep = DAY_MS;\n }\n\n if (hi.getTime() - lo.getTime() <= DAY_MS) break;\n }\n\n // 4) Finish with a short binary search between [lo (empty), hi (found)].\n while (hi.getTime() - lo.getTime() > DAY_MS) {\n const mid = new Date(lo.getTime() + Math.floor((hi.getTime() - lo.getTime()) / 2));\n logger.info(`Binary probe before=${mid.toISOString()}…`);\n\n const hit = await fetchOne(\n sombra,\n partition,\n withBeforeBound(mode, baseFilter, mid.toISOString()),\n logger,\n );\n\n if (hit) {\n const when = getComparisonTimeForRecord(mode, hit);\n logger.info(`Binary probe found record at ${when.toISOString()}.`);\n hi = when; // there is data before mid -> earliest could be even earlier\n } else {\n logger.info('Binary probe found no record.');\n lo = mid; // still empty -> move low up\n }\n }\n\n const earliestDay = startOfUtcDay(hi);\n logger.info(\n `Earliest day (UTC) resolved to ${earliestDay.toISOString()} (instant ≈ ${hi.toISOString()}).`,\n );\n return earliestDay;\n}\n\n/**\n * Find latest day with data using exponential growth forward from earliest (UTC day math).\n *\n * (Implementation note: per your request, we now fetch a single newest record to infer the latest day.)\n *\n * @param sombra - Sombra\n * @param opts - Options\n * @returns Latest day with data\n */\nexport async function findLatestDayWithData(\n sombra: Got,\n opts: {\n /** Partition */\n partition: string;\n /** Chunking mode */\n mode: ChunkMode;\n /** Base filter */\n baseFilter: PreferencesQueryFilter;\n /** Earliest date */\n earliest: Date; // inclusive day start\n /** Logger */\n logger?: Logger;\n },\n): Promise<Date> {\n const { partition, mode, baseFilter, logger = NOOP_LOGGER } = opts;\n\n logger.info('Latest-day discovery: probing newest record…');\n const latest = await fetchOne(sombra, partition, withBeforeBound(mode, baseFilter), logger);\n if (!latest) {\n logger.info('No records found at all; defaulting latest day to today.');\n return startOfUtcDay(new Date());\n }\n\n const when = getComparisonTimeForRecord(mode, latest);\n logger.info(`Newest record instant is ${when.toISOString()}.`);\n\n const latestDay = startOfUtcDay(when);\n logger.info(\n `Latest day (UTC) resolved to ${latestDay.toISOString()} from instant ${when.toISOString()}.`,\n );\n\n return latestDay;\n}\n/* eslint-enable max-lines */\n","import { PreferenceQueryResponseItem } from '@transcend-io/privacy-types';\nimport { decodeCodec } from '@transcend-io/type-utils';\nimport type { Logger } from '@transcend-io/utils';\nimport type { Got } from 'got';\n\nimport { NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { ConsentPreferenceResponse, type PreferencesQueryFilter } from './types.js';\nimport { withPreferenceRetry } from './withPreferenceRetry.js';\n\n/**\n * Fetch consent preferences for the managed consent database (new query endpoint)\n *\n * Uses POST /v1/preferences/{partition}/query with cursor pagination.\n *\n * If `onItems` is provided, this streams pages to the callback and does not\n * accumulate results in memory. If omitted, the function returns all items.\n *\n * @param sombra - Sombra instance (must include auth headers)\n * @param options - Query options\n * @returns All nodes (only when onItems is not provided)\n */\nexport async function fetchConsentPreferences(\n sombra: Got,\n {\n partition,\n filterBy = {},\n limit = 50,\n onItems,\n logger = NOOP_LOGGER,\n }: {\n /** Partition key to fetch (moved to URL path on new endpoint) */\n partition: string;\n /** Query filter (wrapped under \"filter\" in request body) */\n filterBy?: PreferencesQueryFilter;\n /** Number of users per page (1–50 per API spec) */\n limit?: number;\n /** Optional streaming sink; if provided, pages are not accumulated */\n onItems?: (items: PreferenceQueryResponseItem[]) => Promise<void> | void;\n logger?: Logger;\n },\n): Promise<PreferenceQueryResponseItem[]> {\n const collected: PreferenceQueryResponseItem[] = [];\n\n // Cursor-based pagination per new endpoint\n let cursor: string | undefined;\n\n // Build the filter payload, omitting empty filter\n const hasFilter =\n filterBy &&\n (Object.keys(filterBy).length > 0 ||\n (filterBy.system && Object.keys(filterBy.system).length > 0));\n\n // Enforce API max (defensive; backend also validates)\n const pageSize = Math.max(1, Math.min(50, limit ?? 50));\n\n // Keep fetching until no cursor is returned\n // (The API returns an opaque cursor string for the next page)\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const body: {\n /** Filter by user identifiers (new shape) */\n filter?: PreferencesQueryFilter;\n /** Cursor for pagination */\n cursor?: string;\n /** Number of records per page */\n limit: number;\n } = { limit: pageSize };\n\n if (hasFilter) {\n body.filter = filterBy;\n }\n if (cursor) {\n body.cursor = cursor;\n }\n\n const response = await withPreferenceRetry(\n 'Preference Query',\n () =>\n sombra\n .post(`v1/preferences/${partition}/query`, {\n json: body,\n })\n .json(),\n {\n logger,\n onRetry: (attempt, _error, message) => {\n logger.warn(\n `Retry attempt ${attempt} for fetchConsentPreferences due to error: ${message}`,\n );\n },\n },\n );\n\n const { nodes, cursor: nextCursor } = decodeCodec(ConsentPreferenceResponse, response);\n\n if (!nodes || nodes.length === 0) {\n break;\n }\n\n if (onItems) {\n await onItems(nodes);\n } else {\n collected.push(...nodes);\n }\n\n if (!nextCursor) {\n break;\n }\n cursor = nextCursor;\n }\n\n return onItems ? [] : collected;\n}\n","import { PreferenceQueryResponseItem } from '@transcend-io/privacy-types';\nimport { decodeCodec } from '@transcend-io/type-utils';\nimport { map, type Logger } from '@transcend-io/utils';\nimport type { Got } from 'got';\nimport { chunk } from 'lodash-es';\n\nimport { NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { ConsentPreferenceResponse } from './types.js';\nimport { withPreferenceRetry } from './withPreferenceRetry.js';\n\n/**\n * Grab the current consent preference values for a list of identifiers\n *\n * @param sombra - Backend to make API call to\n * @param options - Options\n * @returns Plaintext context information\n */\nexport async function getPreferencesForIdentifiers(\n sombra: Got,\n {\n identifiers,\n partitionKey,\n skipLogging = false,\n concurrency = 40,\n logger = NOOP_LOGGER,\n onProgress,\n }: {\n /** The list of identifiers to look up */\n identifiers: {\n /** The value of the identifier */\n value: string;\n }[];\n /** The partition key to look up */\n partitionKey: string;\n /** Whether to skip logging */\n skipLogging?: boolean;\n /** Concurrency for requests (default 40) */\n concurrency?: number;\n /** Logger */\n logger?: Logger;\n /** Optional progress callback (completed count, total identifiers) */\n onProgress?: (completed: number, total: number) => void;\n },\n): Promise<PreferenceQueryResponseItem[]> {\n const results: PreferenceQueryResponseItem[] = [];\n const groupedIdentifiers = chunk(identifiers, 100);\n\n const t0 = new Date().getTime();\n\n let total = 0;\n await map(\n groupedIdentifiers,\n async (group) => {\n const rawResult = await withPreferenceRetry(\n 'Preference Query',\n () =>\n sombra\n .post(`v1/preferences/${partitionKey}/query`, {\n json: {\n filter: { identifiers: group },\n limit: group.length,\n },\n })\n .json(),\n {\n logger,\n onRetry: (attempt, _err, msg) => {\n logger.warn(\n `[RETRY] group size=${group.length} partition=${partitionKey} attempt=${attempt}: ${msg}`,\n );\n },\n },\n );\n\n const result = decodeCodec(ConsentPreferenceResponse, rawResult);\n results.push(...result.nodes);\n total += group.length;\n onProgress?.(total, identifiers.length);\n },\n {\n concurrency,\n },\n );\n\n const t1 = new Date().getTime();\n const totalTime = t1 - t0;\n\n if (!skipLogging) {\n logger.info(`Completed download in \"${totalTime / 1000}\" seconds.`);\n }\n\n return results;\n}\n","import type { PreferenceQueryResponseItem } from '@transcend-io/privacy-types';\nimport { addDaysUtc, clampPageSize, map as pmap, type Logger } from '@transcend-io/utils';\nimport type { Got } from 'got';\n\nimport { NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { buildConsentChunks } from './buildConsentChunks.js';\nimport {\n findEarliestDayWithData,\n findLatestDayWithData,\n getBoundsFromConsentFilter,\n} from './discoverConsentWindow.js';\nimport { iterateConsentPages } from './iterateConsentPages.js';\nimport { pickConsentChunkMode } from './pickConsentChunkMode.js';\nimport { type PreferencesQueryFilter, type ChunkMode } from './types.js';\n\n/**\n * Merge baseFilter with a window filter, taking care not to mix timestamp/updated fields improperly.\n *\n * @param mode - The chunking mode\n * @param base - The base filter\n * @param window - The per-chunk window filter\n * @returns merged filter\n */\nfunction mergeFilter(\n mode: ChunkMode,\n base: PreferencesQueryFilter,\n window: PreferencesQueryFilter,\n): PreferencesQueryFilter {\n if (mode === 'timestamp') {\n return {\n ...base,\n timestampAfter: window.timestampAfter ?? base.timestampAfter,\n timestampBefore: window.timestampBefore ?? base.timestampBefore,\n // ensure we don't pass `system.*` when chunking by timestamp\n system: undefined,\n };\n }\n // mode === 'updated'\n return {\n ...base,\n system: {\n ...base.system,\n ...(window.system?.updatedAfter ? { updatedAfter: window.system.updatedAfter } : {}),\n ...(window.system?.updatedBefore ? { updatedBefore: window.system.updatedBefore } : {}),\n },\n // Ensure we don't mix dimensions\n timestampAfter: undefined,\n timestampBefore: undefined,\n };\n}\n\n/**\n * High-level chunked fetch with optional progress callback.\n *\n * If an `onItems` callback is provided, pages are streamed to the callback\n * as they are fetched (no accumulation in memory). If no callback is provided,\n * the function returns all items (legacy behavior).\n *\n * @param sombra - Got instance\n * @param options - Options\n * @returns preference items (only if onItems is not provided)\n */\nexport async function fetchConsentPreferencesChunked(\n sombra: Got,\n {\n partition,\n filterBy = {},\n limit = 50,\n windowConcurrency = 25,\n maxChunks = 5000,\n maxLookbackDays = 3650,\n onItems,\n logger = NOOP_LOGGER,\n onProgress,\n }: {\n /** Partition */\n partition: string;\n /** Filter by preferences */\n filterBy?: PreferencesQueryFilter;\n /** Limit number of results (page size) */\n limit?: number;\n /** Window concurrency */\n windowConcurrency?: number;\n /** Max chunks */\n maxChunks?: number; // up to N chunks; min 1 hour per chunk\n /** Max lookback days for discovering bounds */\n maxLookbackDays?: number;\n /** Optional streaming sink; if provided, items are not accumulated */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n onItems?: (items: PreferenceQueryResponseItem[]) => Promise<any> | any;\n /** Logger */\n logger?: Logger;\n /** Optional progress: completed chunks, total chunks, records fetched so far */\n onProgress?: (completed: number, total: number, fetched: number) => void;\n },\n): Promise<PreferenceQueryResponseItem[]> {\n const mode: ChunkMode = pickConsentChunkMode(filterBy);\n logger.info(\n `Fetching consent preferences in chunks by ${\n mode === 'timestamp' ? 'timestamp' : 'system.updatedAt'\n }...`,\n );\n\n // Resolve / discover bounds (UTC)\n let { after, before } = getBoundsFromConsentFilter(mode, filterBy);\n logger.info(\n `Initial bounds: after=${after?.toISOString() ?? 'undefined'} before=${\n before?.toISOString() ?? 'undefined'\n }`,\n );\n\n if (!after || !before) {\n if (!after) {\n logger.info(`Discovering earliest day with data for partition ${partition}...`);\n after = await findEarliestDayWithData(sombra, {\n partition,\n mode,\n baseFilter: filterBy,\n maxLookbackDays,\n logger,\n });\n logger.info(`Discovered earliest day with data: ${after.toISOString()}`);\n }\n if (!before) {\n logger.info(`Discovering latest day with data for partition ${partition}...`);\n const latestDay = await findLatestDayWithData(sombra, {\n partition,\n mode,\n baseFilter: filterBy,\n earliest: after,\n logger,\n });\n // Exclusive upper bound = latest day start + 1 day (UTC)\n before = addDaysUtc(latestDay, 1);\n logger.info(`Discovered latest day with data: ${latestDay.toISOString()}`);\n }\n }\n\n logger.info(`Final bounds (UTC): after=${after.toISOString()} before=${before.toISOString()}`);\n\n // Build up to `maxChunks` chunks, min 1 hour each\n const chunks = buildConsentChunks(mode, after, before, maxChunks);\n\n logger.info(\n `Fetching consent preferences from partition ${partition} in ${chunks.length} chunks...`,\n );\n\n let completed = 0; // finished chunks (out-of-order)\n let fetched = 0; // raw records counter\n\n const t0 = Date.now();\n const pageSize = clampPageSize(limit);\n\n // If we are streaming, do not accumulate everything in memory.\n const out: PreferenceQueryResponseItem[] = [];\n\n await pmap(\n chunks.map((windowFilter, idx) => ({ windowFilter, idx })),\n async ({ windowFilter }) => {\n const filter = mergeFilter(mode, filterBy, windowFilter);\n\n // Stream this chunk page-by-page\n for await (const page of iterateConsentPages(sombra, partition, filter, pageSize, logger)) {\n fetched += page.length;\n onProgress?.(completed, chunks.length, fetched);\n\n if (onItems) {\n await onItems(page);\n } else {\n out.push(...page);\n }\n }\n\n completed += 1;\n onProgress?.(completed, chunks.length, fetched);\n },\n { concurrency: Math.max(1, windowConcurrency) },\n );\n\n onProgress?.(completed, chunks.length, fetched);\n\n logger.info(\n `Fetched ${fetched} consent preference records from partition ${partition} in ${\n (Date.now() - t0) / 1000\n }s.`,\n );\n\n return onItems ? [] : out;\n}\n","import type { Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\n\nimport { fetchAllIdentifiers, type Identifier } from '../data-inventory/fetchAllIdentifiers.js';\nimport { fetchAllPreferenceTopics, type PreferenceTopic } from './fetchAllPreferenceTopics.js';\nimport { fetchAllPurposes, type Purpose } from './fetchAllPurposes.js';\n\nexport interface PreferenceUploadReferenceData {\n /** List of purposes in the organization */\n purposes: Purpose[];\n /** List of preference topics in the organization */\n preferenceTopics: PreferenceTopic[];\n /** List of identifiers in the organization */\n identifiers: Identifier[];\n}\n\n/**\n * Load all required reference data for an upload run.\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Reference data arrays\n */\nexport async function loadReferenceData(\n client: GraphQLClient,\n { logger }: { logger: Logger },\n): Promise<PreferenceUploadReferenceData> {\n const [purposes, preferenceTopics, identifiers] = await Promise.all([\n fetchAllPurposes(client, { logger }),\n fetchAllPreferenceTopics(client, { logger }),\n fetchAllIdentifiers(client, { logger }),\n ]);\n return { purposes, preferenceTopics, identifiers };\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const ATTRIBUTES = gql`\n query TranscendCliAttributes($first: Int!, $offset: Int!) {\n attributeKeys(first: $first, offset: $offset, useMaster: false) {\n nodes {\n id\n isCustom\n description\n enabledOn\n name\n type\n }\n }\n }\n`;\n\nexport const CREATE_ATTRIBUTE_VALUES = gql`\n mutation TranscendCliCreateAttributeValues($input: [CreateAttributeValuesInput!]!) {\n createAttributeValues(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const UPDATE_ATTRIBUTE_VALUES = gql`\n mutation TranscendCliUpdateAttributeValues($input: [UpdateAttributeValueInput!]!) {\n updateAttributeValues(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const DELETE_ATTRIBUTE_VALUE = gql`\n mutation TranscendCliDeleteAttributeValue($id: ID!) {\n deleteAttributeValue(id: $id) {\n clientMutationId\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const ATTRIBUTE_VALUES = gql`\n query TranscendCliAttributeValues($first: Int!, $offset: Int!, $attributeKeyId: ID!) {\n attributeValues(\n first: $first\n offset: $offset\n useMaster: false\n filterBy: { attributeKeys: [$attributeKeyId] }\n ) {\n nodes {\n id\n name\n description\n color\n }\n }\n }\n`;\n\nexport const CREATE_ATTRIBUTE = gql`\n mutation TranscendCliCreateAttribute(\n $name: String!\n $type: AttributeKeyType!\n $description: String\n $enabledOn: [AttributeSupportedResourceType!]\n ) {\n createAttributeKey(\n input: { name: $name, type: $type, description: $description, enabledOn: $enabledOn }\n ) {\n clientMutationId\n attributeKey {\n id\n }\n }\n }\n`;\n\nexport const UPDATE_ATTRIBUTE = gql`\n mutation TranscendCliCreateAttribute(\n $attributeKeyId: ID!\n $description: String\n $enabledOn: [AttributeSupportedResourceType!]\n ) {\n updateAttributeKey(\n input: { id: $attributeKeyId, description: $description, enabledOn: $enabledOn }\n ) {\n clientMutationId\n attributeKey {\n id\n }\n }\n }\n`;\n\nexport const SET_RESOURCE_ATTRIBUTES = gql`\n mutation TranscendCliSetResourceAttributes($input: SetResourceAttributesInput!) {\n setResourceAttributes(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { AttributeKeyType, AttributeSupportedResourceType } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { ATTRIBUTES, ATTRIBUTE_VALUES } from './gqls/attribute.js';\n\nexport interface AttributeValue {\n /** Attribute ID */\n id: string;\n /** Attribute name */\n name: string;\n /** Attribute description */\n description: string;\n /** Color of attribute value */\n color: string;\n}\n\nexport interface Attribute {\n /** ID of attribute */\n id: string;\n /** Name of attribute */\n name: string;\n /** if custom attribute */\n isCustom: boolean;\n /** Description */\n description: string;\n /** Type of attribute */\n type: AttributeKeyType;\n /** Values */\n values: AttributeValue[];\n /** The different fields that the attribute is enabled on */\n enabledOn: AttributeSupportedResourceType[];\n}\n\nconst PAGE_SIZE = 100;\n\n/**\n * Fetch all attribute values for an attribute key\n *\n * @param client - GraphQL client\n * @param attributeKeyId - Attribute keyID\n * @returns A map from apiKey title to Identifier\n */\nexport async function fetchAllAttributeValues(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy: {\n /** Attribute key ID */\n attributeKeyId: string;\n };\n },\n): Promise<AttributeValue[]> {\n const {\n logger,\n filterBy: { attributeKeyId },\n } = options;\n const attributeValues: AttributeValue[] = [];\n let offset = 0;\n\n // Paginate\n let shouldContinue = false;\n do {\n const {\n attributeValues: { nodes },\n } = await makeGraphQLRequest<{\n /** Query response */\n attributeValues: {\n /** List of matches */\n nodes: AttributeValue[];\n };\n }>(client, ATTRIBUTE_VALUES, {\n variables: { first: PAGE_SIZE, offset, attributeKeyId },\n logger,\n });\n attributeValues.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return attributeValues.sort((a, b) => a.name.localeCompare(b.name));\n}\n\nexport const SYNC_ATTRIBUTE_TYPES = [AttributeKeyType.MultiSelect, AttributeKeyType.SingleSelect];\n\n/**\n * Fetch all attributes in an organization\n *\n * @param client - GraphQL client\n * @returns A map from apiKey title to Identifier\n */\nexport async function fetchAllAttributes(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Attribute[]> {\n const { logger } = options;\n const attributes: Attribute[] = [];\n let offset = 0;\n\n // Paginate\n let shouldContinue = false;\n do {\n const {\n attributeKeys: { nodes },\n } = await makeGraphQLRequest<{\n /** Query response */\n attributeKeys: {\n /** List of matches */\n nodes: Attribute[];\n };\n }>(client, ATTRIBUTES, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n attributes.push(\n ...(await Promise.all(\n nodes.map(async (node) => ({\n ...node,\n values: SYNC_ATTRIBUTE_TYPES.includes(node.type)\n ? await fetchAllAttributeValues(client, {\n logger,\n filterBy: { attributeKeyId: node.id },\n })\n : [],\n })),\n )),\n );\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return attributes.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\nexport const MESSAGES = gql`\n query TranscendCliFetchMessage {\n translatedMessages {\n id\n defaultMessage\n description\n targetReactIntlId\n translations {\n locale\n value\n }\n }\n }\n`;\n\nexport const UPDATE_INTL_MESSAGES = gql`\n mutation TranscendCliUpdateIntlMessages($messages: [MessageInput!]!) {\n updateIntlMessages(input: { messages: $messages, skipPublish: true }) {\n clientMutationId\n }\n }\n`;\n","import type { LocaleValue } from '@transcend-io/internationalization';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { MESSAGES } from './gqls/message.js';\n\nexport interface Message {\n /** ID of message */\n id: string;\n /** Default message */\n defaultMessage: string;\n /** Description */\n description: string;\n /** React Intl ID */\n targetReactIntlId: string | null;\n /** Disabled locales */\n translations: {\n /** Locale */\n locale: LocaleValue;\n /** Value */\n value: string;\n }[];\n}\n\n/**\n * Fetch all messages in the organization\n *\n * @param client - GraphQL client\n * @returns All messages in the organization\n */\nexport async function fetchAllMessages(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Message[]> {\n const { logger } = options;\n const { translatedMessages } = await makeGraphQLRequest<{\n /** Messages */\n translatedMessages: Message[];\n }>(client, MESSAGES, { logger });\n return translatedMessages;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const TEAMS = gql`\n query TranscendCliTeams($first: Int!, $offset: Int!, $input: TeamFiltersInput) {\n teams(\n first: $first\n offset: $offset\n filterBy: $input\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n description\n ssoDepartment\n ssoGroup\n ssoTitle\n users {\n id\n email\n name\n }\n scopes {\n id\n name\n title\n }\n }\n }\n }\n`;\n\nexport const CREATE_TEAM = gql`\n mutation TranscendCliCreateTeam($input: TeamInput!) {\n createTeam(input: $input) {\n team {\n id\n name\n }\n }\n }\n`;\n\nexport const UPDATE_TEAM = gql`\n mutation TranscendCliUpdateTeam($input: UpdateTeamInput!) {\n updateTeam(input: $input) {\n team {\n id\n name\n }\n }\n }\n`;\n","import { ScopeName } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { TEAMS } from './gqls/team.js';\n\nexport interface Team {\n /** ID of team */\n id: string;\n /** Name of team */\n name: string;\n /** Description of team */\n description: string;\n /** SSO department for automated provisioning */\n ssoDepartment?: string;\n /** SSO group name for automated provisioning */\n ssoGroup?: string;\n /** SSO title mapping for automated provisioning */\n ssoTitle?: string;\n /** List of users on the team */\n users: {\n /** ID of user */\n id: string;\n /** Email of user */\n email: string;\n /** Name of user */\n name: string;\n }[];\n /** List of scopes on the team */\n scopes: {\n /** ID of scope */\n id: string;\n /** Name of scope */\n name: ScopeName;\n /** Title of scope */\n title: string;\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all teams in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All teams in the organization\n */\nexport async function fetchAllTeams(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Team[]> {\n const { logger } = options;\n const teams: Team[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n teams: { nodes },\n } = await makeGraphQLRequest<{\n /** Teams */\n teams: {\n /** List */\n nodes: Team[];\n };\n }>(client, TEAMS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n teams.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return teams.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const USERS = gql`\n query TranscendCliUsers($first: Int!, $offset: Int!, $input: UserFiltersInput) {\n users(\n first: $first\n offset: $offset\n filterBy: $input\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n email\n }\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { USERS } from './gqls/user.js';\n\nexport interface User {\n /** ID of user */\n id: string;\n /** Name of user */\n name: string;\n /** Email of user */\n email: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all users in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All users in the organization\n */\nexport async function fetchAllUsers(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<User[]> {\n const { logger } = options;\n const users: User[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n users: { nodes },\n } = await makeGraphQLRequest<{\n /** Users */\n users: {\n /** List */\n nodes: User[];\n };\n }>(client, USERS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n users.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return users.sort((a, b) => a.email.localeCompare(b.email));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const API_KEYS = gql`\n query TranscendCliApiKeys($first: Int!, $offset: Int!, $titles: [String!]) {\n apiKeys(\n first: $first\n offset: $offset\n filterBy: { titles: $titles }\n useMaster: false\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n ) {\n nodes {\n id\n title\n }\n }\n }\n`;\n\nexport const CREATE_API_KEY = gql`\n mutation TranscendCliCreateApiKey($input: ApiKeyInput!) {\n createApiKey(input: $input) {\n apiKey {\n id\n apiKey\n title\n }\n }\n }\n`;\n\nexport const DELETE_API_KEY = gql`\n mutation TranscendCliDeleteApiKey($id: ID!) {\n deleteApiKey(id: $id) {\n clientMutationId\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy, uniq, difference } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { API_KEYS } from './gqls/apiKey.js';\n\nexport interface ApiKey {\n /** ID of API key */\n id: string;\n /** Title of API key */\n title: string;\n}\n\nexport interface FetchApiKeysInput {\n /** API key definitions */\n 'api-keys'?: {\n /** Title of API key */\n title: string;\n }[];\n /** Data silo definitions that may reference API keys */\n 'data-silos'?: {\n /** Title of the API key to use */\n 'api-key-title'?: string;\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\nconst ADMIN_LINK = 'https://app.transcend.io/infrastructure/api-keys';\n\n/**\n * Fetch all API keys in an organization\n *\n * @param client - Client\n * @param options - Options\n * @returns API keys\n */\nexport async function fetchAllApiKeys(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** Filter on titles */\n titles?: string[];\n };\n } = {},\n): Promise<ApiKey[]> {\n const { logger = NOOP_LOGGER, filterBy: { titles } = {} } = options;\n const apiKeys: ApiKey[] = [];\n let offset = 0;\n\n // Paginate\n let shouldContinue = false;\n do {\n const {\n apiKeys: { nodes },\n } = await makeGraphQLRequest<{\n /** API keys */\n apiKeys: {\n /** List */\n nodes: ApiKey[];\n };\n }>(client, API_KEYS, {\n variables: { first: PAGE_SIZE, offset, titles },\n logger,\n });\n apiKeys.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n return apiKeys.sort((a, b) => a.title.localeCompare(b.title));\n}\n\n/**\n * Fetch all apiKeys and if any are found in the config that are\n * missing, create those apiKeys.\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns A map from apiKey title to Identifier\n */\nexport async function fetchApiKeys(\n client: GraphQLClient,\n options: {\n /** API key input configuration */\n apiKeyInputs?: FetchApiKeysInput;\n /** When true, fetch all API keys */\n fetchAll?: boolean;\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<{ [k in string]: ApiKey }> {\n const {\n apiKeyInputs: { 'api-keys': apiKeyDefs = [], 'data-silos': dataSilos = [] } = {},\n fetchAll = false,\n logger = NOOP_LOGGER,\n } = options;\n logger.info(`Fetching ${fetchAll ? 'all' : apiKeyDefs.length} API keys...`);\n const titles = apiKeyDefs.map(({ title }) => title);\n const expectedApiKeyTitles = uniq(\n dataSilos.map((silo) => silo['api-key-title']).filter((x): x is string => !!x),\n );\n const allTitlesExpected = [...expectedApiKeyTitles, ...titles];\n const apiKeys = await fetchAllApiKeys(client, {\n logger,\n filterBy: {\n titles: fetchAll ? undefined : [...expectedApiKeyTitles, ...titles],\n },\n });\n\n // Create a map\n const apiKeysByTitle = keyBy(apiKeys, 'title');\n\n // Determine expected set of apiKeys expected\n const missingApiKeys = difference(\n allTitlesExpected,\n apiKeys.map(({ title }) => title),\n );\n\n // If there are missing apiKeys, throw an error\n if (missingApiKeys.length > 0) {\n logger.error(\n `Failed to find API keys \"${missingApiKeys.join(\n '\", \"',\n )}\"! Make sure these API keys are created at: ${ADMIN_LINK}`,\n );\n process.exit(1);\n }\n return apiKeysByTitle;\n}\n","import { IsoCountrySubdivisionCode, IsoCountryCode } from '@transcend-io/privacy-types';\n\nexport interface RegionInput {\n /** The country */\n country?: IsoCountryCode;\n /** The country subdivision */\n countrySubDivision?: IsoCountrySubdivisionCode;\n}\n\n// Country subdivision is nullable in DB\nexport interface Region {\n /** Country */\n country: IsoCountryCode;\n /** Sub division (may be null in DB) */\n countrySubDivision?: IsoCountrySubdivisionCode | null;\n}\n\n/**\n * Format regions list to remove null country subdivisions\n *\n * @param vals - Regions\n * @returns formatted regions\n */\nexport function formatRegions(vals: Region[]): RegionInput[] {\n return vals.map(({ country, countrySubDivision }) => ({\n country,\n ...(countrySubDivision ? { countrySubDivision } : {}),\n }));\n}\n","import { gql } from 'graphql-request';\n\nexport const DETERMINE_LOGIN_METHOD = gql`\n mutation TranscendCliDetermineLoginMethod($email: String!) {\n determineLoginMethod(input: { email: $email }) {\n loginMethod {\n email\n sombraPublicKey\n }\n }\n }\n`;\n\nexport const LOGIN = gql`\n mutation TranscendCliLogin($email: String!, $password: String!, $publicKey: String!) {\n login(input: { email: $email, password: $password }, publicKey: $publicKey) {\n user {\n roles {\n id\n organization {\n name\n id\n uri\n parentOrganizationId\n }\n }\n }\n }\n }\n`;\n\nexport const ASSUME_ROLE = gql`\n mutation TranscendCliAssumeRole($id: ID!, $publicKey: String!) {\n assumeRole(id: $id, publicKey: $publicKey) {\n clientMutationId\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { DETERMINE_LOGIN_METHOD, ASSUME_ROLE, LOGIN } from './gqls/auth.js';\n\nexport interface OrganizationPreview {\n /** Name of organization */\n name: string;\n /** Id of organization */\n id: string;\n /** uri of organization */\n uri: string;\n /** ID of parent organization */\n parentOrganizationId?: string;\n}\n\nexport interface UserRole {\n /** ID of role */\n id: string;\n /** Related organization */\n organization: OrganizationPreview;\n}\n\n/**\n * Log in as a user\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Cookie and roles\n */\nexport async function loginUser(\n client: GraphQLClient,\n options: {\n /** Email of user */\n email: string;\n /** Password of user */\n password: string;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<{\n /** Cookie to be used to make subsequent requests */\n loginCookie: string;\n /** Roles of the user */\n roles: UserRole[];\n}> {\n const { email, password, logger } = options;\n\n const {\n determineLoginMethod: { loginMethod },\n } = await makeGraphQLRequest<{\n /** Determine login method */\n determineLoginMethod: {\n /** Login method info */\n loginMethod: {\n /** Email being logged in */\n email: string;\n /** Sombra public key */\n sombraPublicKey: string;\n };\n };\n }>(client, DETERMINE_LOGIN_METHOD, {\n variables: { email },\n logger,\n });\n\n const res = await client.rawRequest<{\n /** Login */\n login: {\n /** User */\n user: {\n /** Roles of user */\n roles: UserRole[];\n };\n };\n }>(LOGIN, {\n email,\n password,\n publicKey: loginMethod.sombraPublicKey,\n });\n const {\n login: { user },\n } = res.data;\n\n // Get login cookie from response\n const loginCookie = res.headers.get('set-cookie');\n if (!loginCookie || !loginCookie.includes('laravel')) {\n throw new Error('Failed to get login cookie in response');\n }\n\n return {\n roles: user.roles,\n loginCookie,\n };\n}\n\n/**\n * Assume role for user into another organization\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function assumeRole(\n client: GraphQLClient,\n options: {\n /** Email of user */\n email: string;\n /** Role of user assuming into */\n roleId: string;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { email, roleId, logger } = options;\n\n const {\n determineLoginMethod: { loginMethod },\n } = await makeGraphQLRequest<{\n /** Determine login method */\n determineLoginMethod: {\n /** Login method info */\n loginMethod: {\n /** Email being logged in */\n email: string;\n /** Sombra public key */\n sombraPublicKey: string;\n };\n };\n }>(client, DETERMINE_LOGIN_METHOD, {\n variables: { email, userId: roleId },\n logger,\n });\n\n await client.rawRequest<{\n /** Assume role */\n assumeRole: {\n /** Mutation ID */\n clientMutationId: string;\n };\n }>(ASSUME_ROLE, {\n id: roleId,\n publicKey: loginMethod.sombraPublicKey,\n });\n}\n","import { ScopeName } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { CREATE_API_KEY, DELETE_API_KEY } from './gqls/apiKey.js';\n\nexport interface CreatedApiKey {\n /** ID of API key */\n id: string;\n /** Actual API key */\n apiKey: string;\n /** Title of the API key */\n title: string;\n}\n\n/**\n * Create an API key\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns The API key\n */\nexport async function createApiKey(\n client: GraphQLClient,\n options: {\n /** Input for creating an API key */\n input: {\n /** Title of API key */\n title: string;\n /** Scopes for API key */\n scopes: ScopeName[];\n };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<CreatedApiKey> {\n const {\n input: { title, scopes },\n logger,\n } = options;\n const {\n createApiKey: { apiKey },\n } = await makeGraphQLRequest<{\n /** Create API key */\n createApiKey: {\n /** API key */\n apiKey: CreatedApiKey;\n };\n }>(client, CREATE_API_KEY, { variables: { input: { title, scopes } }, logger });\n\n return apiKey;\n}\n\n/**\n * Delete an API key\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function deleteApiKey(\n client: GraphQLClient,\n options: {\n /** API key ID to delete */\n id: string;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { id, logger } = options;\n await makeGraphQLRequest(client, DELETE_API_KEY, { variables: { id }, logger });\n}\n","import { AttributeSupportedResourceType } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { SET_RESOURCE_ATTRIBUTES } from './gqls/attribute.js';\n\ninterface SetResourceAttributesInput {\n /** ID of resource */\n resourceId: string;\n /** Type of resource */\n resourceType: AttributeSupportedResourceType;\n /** Attribute key ID */\n attributeKeyId: string;\n /** Attribute values by ID */\n attributeValueIds?: string[];\n /** Attribute values by name */\n attributeValueNames?: string[];\n}\n\n/**\n * Set attribute values on a particular resource\n *\n * @param client - GraphQL client\n * @param input - Input\n */\nexport async function setResourceAttributes(\n client: GraphQLClient,\n input: SetResourceAttributesInput,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n const { logger } = options;\n await makeGraphQLRequest(client, SET_RESOURCE_ATTRIBUTES, {\n variables: { input },\n logger,\n });\n}\n","import { AttributeKeyType, AttributeSupportedResourceType } from '@transcend-io/privacy-types';\nimport { map, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy, difference, groupBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { type Attribute } from './fetchAllAttributes.js';\nimport {\n CREATE_ATTRIBUTE,\n CREATE_ATTRIBUTE_VALUES,\n DELETE_ATTRIBUTE_VALUE,\n UPDATE_ATTRIBUTE,\n UPDATE_ATTRIBUTE_VALUES,\n} from './gqls/attribute.js';\n\nexport interface AttributeValueInput {\n /** Name of attribute value */\n name: string;\n /** Description */\n description?: string;\n /** Color */\n color?: string;\n}\n\nexport interface AttributeInput {\n /** Name of attribute */\n name: string;\n /** Type of attribute */\n type: AttributeKeyType;\n /** Description of attribute */\n description?: string;\n /** Resource types that the attribute is enabled on */\n resources?: AttributeSupportedResourceType[];\n /** Values of attribute */\n values?: AttributeValueInput[];\n}\n\n/**\n * Sync attribute\n *\n * @param client - GraphQL client\n * @param attribute - The attribute input\n * @param options - Options\n */\nexport async function syncAttribute(\n client: GraphQLClient,\n attribute: AttributeInput,\n {\n existingAttribute,\n deleteExtraAttributeValues,\n logger = NOOP_LOGGER,\n }: {\n /** The existing attribute configuration if it exists */\n existingAttribute?: Attribute;\n /** When true, delete extra attributes not specified in the list of values */\n deleteExtraAttributeValues?: boolean;\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n // attribute key input\n const input = {\n name: attribute.name,\n enabledOn: attribute.resources,\n };\n\n // create or update attribute key\n let attributeKeyId: string;\n if (!existingAttribute) {\n const {\n createAttributeKey: { attributeKey },\n } = await makeGraphQLRequest<{\n /** Create attribute key response */\n createAttributeKey: {\n /** Attribute key */\n attributeKey: {\n /** ID */\n id: string;\n };\n };\n }>(client, CREATE_ATTRIBUTE, {\n variables: {\n type: attribute.type,\n description: attribute.description,\n ...input,\n },\n logger,\n });\n attributeKeyId = attributeKey.id;\n } else {\n await makeGraphQLRequest(client, UPDATE_ATTRIBUTE, {\n variables: {\n attributeKeyId: existingAttribute.id,\n description: existingAttribute.isCustom ? attribute.description : undefined,\n ...input,\n },\n logger,\n });\n attributeKeyId = existingAttribute.id;\n }\n\n // upsert attribute values\n const existingAttributeMap = keyBy(existingAttribute?.values || [], 'name');\n const { existingValues = [], newValues = [] } = groupBy(attribute.values || [], (field) =>\n existingAttributeMap[field.name] ? 'existingValues' : 'newValues',\n );\n const removedValues = difference(\n (existingAttribute?.values || []).map(({ name }) => name),\n (attribute.values || []).map(({ name }) => name),\n );\n\n // Create new attribute values\n if (newValues.length > 0) {\n await makeGraphQLRequest(client, CREATE_ATTRIBUTE_VALUES, {\n variables: {\n input: newValues.map(({ name, ...rest }) => ({\n name,\n attributeKeyId,\n ...rest,\n })),\n },\n logger,\n });\n logger.info(`Created ${newValues.length} attribute values`);\n }\n\n // Update existing attribute values\n if (existingValues.length > 0) {\n await makeGraphQLRequest(client, UPDATE_ATTRIBUTE_VALUES, {\n variables: {\n input: existingValues.map(({ name, ...rest }) => ({\n id: existingAttributeMap[name]!.id,\n name,\n description: existingAttributeMap[name]!.description,\n color: existingAttributeMap[name]!.color,\n ...rest,\n attributeKeyId,\n })),\n },\n logger,\n });\n logger.info(`Updated ${existingValues.length} attribute values`);\n }\n\n // Delete removed attribute values\n if (removedValues.length > 0 && deleteExtraAttributeValues) {\n await map(\n removedValues,\n async (value) => {\n await makeGraphQLRequest(client, DELETE_ATTRIBUTE_VALUE, {\n variables: { id: existingAttributeMap[value]!.id },\n logger,\n });\n },\n {\n concurrency: 10,\n },\n );\n logger.info(`Deleted ${removedValues.length} attribute values`);\n }\n}\n","import { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { UPDATE_INTL_MESSAGES } from './gqls/message.js';\n\nexport interface IntlMessageInput {\n /** React Intl message ID */\n id: string;\n /** Target React Intl ID to map this message to */\n targetReactIntlId?: string;\n /** Description of the message for translators */\n description?: string;\n /** Default English message content */\n defaultMessage?: string;\n /** Map from locale code to translated string */\n translations?: Record<string, string>;\n}\n\nconst MAX_PAGE_SIZE = 100;\n\n/**\n * Update or create intl messages\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateIntlMessages(\n client: GraphQLClient,\n options: {\n /** List of message inputs */\n input: IntlMessageInput[];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: messages, logger = NOOP_LOGGER } = options;\n // Batch update messages\n await mapSeries(chunk(messages, MAX_PAGE_SIZE), async (page) => {\n await makeGraphQLRequest(client, UPDATE_INTL_MESSAGES, {\n variables: {\n messages: page.map((message) => ({\n ...(message.id.includes('.') ? {} : { id: message.id }),\n defaultMessage: message.defaultMessage,\n targetReactIntlId: message.targetReactIntlId,\n translations: !message.translations\n ? undefined\n : Object.entries(message.translations).map(([locale, value]) => ({\n locale,\n value,\n })),\n })),\n },\n logger,\n });\n });\n}\n\n/**\n * Sync the set of messages from the YML interface into the product\n *\n * @param client - GraphQL client\n * @param messages - messages to sync\n * @returns True upon success, false upon failure\n */\nexport async function syncIntlMessages(\n client: GraphQLClient,\n messages: IntlMessageInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${messages.length}\" messages...`);\n\n // Ensure no duplicates are being uploaded\n const notUnique = messages.filter(\n (message) => messages.filter((pol) => message.id === pol.id).length > 1,\n );\n if (notUnique.length > 0) {\n throw new Error(\n `Failed to upload messages as there were non-unique entries found: ${notUnique\n .map(({ id }) => id)\n .join(',')}`,\n );\n }\n\n try {\n logger.info(`Upserting \"${messages.length}\" new messages...`);\n await updateIntlMessages(client, { input: messages, logger });\n logger.info(`Successfully synced ${messages.length} messages!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create messages! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import { ScopeName } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllTeams, type Team } from './fetchAllTeams.js';\nimport { UPDATE_TEAM, CREATE_TEAM } from './gqls/team.js';\n\nexport interface TeamInput {\n /** The display name of the team */\n name: string;\n /** Team description */\n description: string;\n /** SSO department for automated provisioning */\n 'sso-department'?: string;\n /** SSO group name for automated provisioning */\n 'sso-group'?: string;\n /** SSO title mapping for automated provisioning */\n 'sso-title'?: string;\n /** List of user emails on the team */\n users?: string[];\n /** List of scopes that the team should have */\n scopes?: ScopeName[];\n}\n\n/**\n * Input to create a new team\n *\n * @param client - GraphQL client\n * @param team - Input\n * @param options - Options\n * @returns Created team\n */\nexport async function createTeam(\n client: GraphQLClient,\n options: {\n /** Team to create */\n input: TeamInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<Team, 'id' | 'name'>> {\n const { input: team, logger = NOOP_LOGGER } = options;\n const input = {\n name: team.name,\n description: team.description,\n ssoTitle: team['sso-title'],\n ssoDepartment: team['sso-department'],\n ssoGroup: team['sso-group'],\n scopes: team.scopes,\n userEmails: team.users,\n };\n\n const { createTeam } = await makeGraphQLRequest<{\n /** Create team mutation */\n createTeam: {\n /** Created team */\n team: Team;\n };\n }>(client, CREATE_TEAM, {\n variables: { input },\n logger,\n });\n return createTeam.team;\n}\n\n/**\n * Input to update teams\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Updated team\n */\nexport async function updateTeam(\n client: GraphQLClient,\n options: {\n /** Team input to update */\n input: TeamInput & {\n /** ID of team to update */\n id: string;\n };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<Team, 'id' | 'name'>> {\n const { input: team, logger = NOOP_LOGGER } = options;\n const teamId = team.id;\n const { updateTeam } = await makeGraphQLRequest<{\n /** Update team mutation */\n updateTeam: {\n /** Updated team */\n team: Team;\n };\n }>(client, UPDATE_TEAM, {\n variables: {\n input: {\n id: teamId,\n name: team.name,\n description: team.description,\n ssoTitle: team['sso-title'],\n ssoDepartment: team['sso-department'],\n ssoGroup: team['sso-group'],\n scopes: team.scopes,\n userEmails: team.users,\n },\n },\n logger,\n });\n return updateTeam.team;\n}\n\n/**\n * Sync the teams\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncTeams(\n client: GraphQLClient,\n inputs: TeamInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n // Fetch existing\n logger.info(`Syncing \"${inputs.length}\" teams...`);\n\n let encounteredError = false;\n\n // Fetch existing\n const existingTeams = await fetchAllTeams(client, { logger });\n\n // Look up by name\n const teamsByName: { [k in string]: Pick<Team, 'id' | 'name'> } = keyBy(existingTeams, 'name');\n\n // Create new teams\n const newTeams = inputs.filter((input) => !teamsByName[input.name]);\n const updatedTeams = inputs.filter((input) => !!teamsByName[input.name]);\n\n // Create new teams\n await mapSeries(newTeams, async (team) => {\n try {\n const newTeam = await createTeam(client, { input: team, logger });\n teamsByName[newTeam.name] = newTeam;\n logger.info(`Successfully created team \"${team.name}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync team \"${team.name}\"! - ${(err as Error).message}`);\n }\n });\n\n // Update all teams\n await mapSeries(updatedTeams, async (input) => {\n try {\n const newTeam = await updateTeam(client, {\n input: { ...input, id: teamsByName[input.name]!.id },\n logger,\n });\n teamsByName[newTeam.name] = newTeam;\n logger.info(`Successfully updated team \"${input.name}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync team \"${input.name}\"! - ${(err as Error).message}`);\n }\n });\n\n return !encounteredError;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\nexport const ATTRIBUTE_KEYS_REQUESTS = gql`\n query TranscendCliAttributeKeys($first: Int!, $offset: Int!) {\n attributeKeys(\n filterBy: { enabledOn: [request] }\n first: $first\n useMaster: false\n offset: $offset\n ) {\n nodes {\n id\n name\n type\n }\n }\n }\n`;\n","import got, { type Got } from 'got';\n\n/**\n * Instantiate an instance of got that is capable of making requests\n * to a sombra gateway.\n *\n * @param transcendUrl - URL of Transcend API\n * @returns The instance of got that is capable of making requests to the customer ingress\n */\nexport function createTranscendConsentGotInstance(transcendUrl: string): Got {\n return (got as unknown as Got).extend({\n prefixUrl: transcendUrl,\n });\n}\n","import { gql } from 'graphql-request';\n\n// ---- FETCH_CONSENT_MANAGER_ID query ----\n\n/** Full response from FETCH_CONSENT_MANAGER_ID */\nexport interface TranscendCliFetchConsentManagerIdResponse {\n /** Consent manager wrapper */\n consentManager: {\n /** Consent manager object */\n consentManager: {\n /** Consent manager / airgap bundle ID */\n id: string;\n };\n };\n}\n\nexport const FETCH_CONSENT_MANAGER_ID = gql`\n query TranscendCliFetchConsentManagerId {\n consentManager {\n consentManager {\n id\n }\n }\n }\n`;\n\n// ---- FETCH_CONSENT_MANAGER query ----\n\n/** Consent manager configuration */\nexport interface TranscendConsentManagerConfigGql {\n /** Configured domains */\n domains: string[];\n /** Consent precedence setting */\n consentPrecedence: string;\n /** Unknown request policy */\n unknownRequestPolicy: string;\n /** Unknown cookie policy */\n unknownCookiePolicy: string;\n /** Sync endpoint URL */\n syncEndpoint: string;\n /** Telemetry partitioning strategy */\n telemetryPartitioning: string;\n /** Signed IAB agreement status */\n signedIabAgreement: string;\n /** Sync groups setting */\n syncGroups: string;\n /** Partition parameter */\n partition: string;\n}\n\n/** Consent manager node */\nexport interface TranscendConsentManagerGql {\n /** Consent manager / airgap bundle ID */\n id: string;\n /** Production bundle URL */\n bundleURL: string;\n /** Test bundle URL */\n testBundleURL: string;\n /** Configuration settings */\n configuration: TranscendConsentManagerConfigGql;\n /** Partition info */\n partition?: {\n /** Partition value */\n partition: string;\n };\n}\n\n/** Full response from FETCH_CONSENT_MANAGER */\nexport interface TranscendCliFetchConsentManagerResponse {\n /** Consent manager wrapper */\n consentManager: {\n /** Consent manager object */\n consentManager: TranscendConsentManagerGql;\n };\n}\n\nexport const FETCH_CONSENT_MANAGER = gql`\n query TranscendCliFetchConsentManager {\n consentManager {\n consentManager {\n id\n bundleURL\n testBundleURL\n configuration {\n domains\n consentPrecedence\n unknownRequestPolicy\n unknownCookiePolicy\n syncEndpoint\n telemetryPartitioning\n signedIabAgreement\n syncGroups\n partition\n }\n partition {\n partition\n }\n }\n }\n }\n`;\n\n// ---- FETCH_CONSENT_MANAGER_THEME query ----\n\n/** Consent manager theme fields */\nexport interface TranscendConsentManagerThemeGql {\n /** Primary color */\n primaryColor: string;\n /** Font color */\n fontColor: string;\n /** Privacy policy URL */\n privacyPolicy?: string;\n /** Auto-prompt setting */\n prompt: number;\n}\n\n/** Full response from FETCH_CONSENT_MANAGER_THEME */\nexport interface TranscendCliFetchConsentManagerThemeResponse {\n /** Theme wrapper */\n consentManagerTheme: {\n /** Theme object */\n theme: TranscendConsentManagerThemeGql;\n };\n}\n\nexport const FETCH_CONSENT_MANAGER_THEME = gql`\n query TranscendCliFetchConsentManagerTheme($airgapBundleId: ID!) {\n consentManagerTheme(input: { airgapBundleId: $airgapBundleId }) {\n theme {\n primaryColor\n fontColor\n privacyPolicy\n prompt\n }\n }\n }\n`;\n\n// ---- Consent Manager mutations ----\n\n/** Shared response type for mutations that return only clientMutationId */\nexport interface TranscendClientMutationIdResponse {\n /** Mutation result keyed by mutation name */\n [key: string]: {\n /** Client mutation ID */\n clientMutationId: string | null;\n };\n}\n\nexport const CREATE_CONSENT_MANAGER = gql`\n mutation TranscendCliCreateConsentManager($privacyCenterId: ID!) {\n createConsentManager(input: { privacyCenterId: $privacyCenterId }) {\n consentManager {\n id\n }\n }\n }\n`;\n\nexport const UPDATE_CONSENT_MANAGER_VERSION = gql`\n mutation TranscendCliUpdateConsentManager($airgapBundleId: ID!, $version: String!) {\n updateConsentManager(id: $airgapBundleId, input: { version: $version }) {\n clientMutationId\n }\n }\n`;\n\nexport const UPDATE_CONSENT_MANAGER_TO_LATEST = gql`\n mutation TranscendCliUpdateConsentManagerToLatest(\n $airgapBundleId: ID!\n $bundleType: ConsentBundleType!\n ) {\n updateConsentManagerToLatestVersion(id: $airgapBundleId, input: { bundleType: $bundleType }) {\n clientMutationId\n }\n }\n`;\n\nexport const DEPLOY_CONSENT_MANAGER = gql`\n mutation TranscendCliDeployConsentManager($airgapBundleId: ID!, $bundleType: ConsentBundleType!) {\n deployConsentManagerBundle(id: $airgapBundleId, input: { bundleType: $bundleType }) {\n clientMutationId\n }\n }\n`;\n\nexport const UPDATE_CONSENT_MANAGER_DOMAINS = gql`\n mutation TranscendCliUpdateConsentManagerDomains($airgapBundleId: ID!, $domains: [String!]!) {\n updateConsentManagerDomains(input: { id: $airgapBundleId, domains: $domains }) {\n clientMutationId\n }\n }\n`;\n\nexport const UPDATE_CONSENT_MANAGER_PARTITION = gql`\n mutation TranscendCliUpdateConsentManagerPartition($airgapBundleId: ID!, $partitionId: ID!) {\n updateConsentManagerPartition(input: { id: $airgapBundleId, partitionId: $partitionId }) {\n clientMutationId\n }\n }\n`;\n\nexport const UPDATE_LOAD_OPTIONS = gql`\n mutation TranscendCliUpdateLoadOptions($input: UpdateLoadOptionsInput!) {\n updateLoadOptions(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const TOGGLE_UNKNOWN_REQUEST_POLICY = gql`\n mutation TranscendCliToggleUnknownRequestPolicy($input: ToggleUnknownRequestPolicyInput!) {\n toggleUnknownRequestPolicy(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const TOGGLE_UNKNOWN_COOKIE_POLICY = gql`\n mutation TranscendCliToggleUnknownCookiePolicy($input: ToggleUnknownCookiePolicyInput!) {\n toggleUnknownCookiePolicy(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const TOGGLE_TELEMETRY_PARTITION_STRATEGY = gql`\n mutation TranscendCliToggleTelemetryPartitionStrategy(\n $input: ToggleTelemetryPartitionStrategyInput!\n ) {\n toggleTelemetryPartitioning(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const TOGGLE_CONSENT_PRECEDENCE = gql`\n mutation TranscendCliToggleConsentPrecedence($input: ToggleConsentPrecedenceInput!) {\n toggleConsentPrecedence(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const UPDATE_CONSENT_MANAGER_THEME = gql`\n mutation TranscendCliUpdateConsentManagerTheme($input: UpdateConsentManagerThemeInput!) {\n updateConsentManagerTheme(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { ConsentBundleType } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { DEPLOY_CONSENT_MANAGER, UPDATE_CONSENT_MANAGER_TO_LATEST } from './gqls/consentManager.js';\n\n/**\n * Deploy the Consent Manager\n *\n * @param client - GraphQL client\n * @param input - Deploy input\n * @param options - Options\n */\nexport async function deployConsentManager(\n client: GraphQLClient,\n input: {\n /** ID of Consent Manager */\n id: string;\n /** Type of bundle */\n bundleType: ConsentBundleType;\n },\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n await makeGraphQLRequest(client, DEPLOY_CONSENT_MANAGER, {\n variables: { airgapBundleId: input.id, bundleType: input.bundleType },\n logger: options.logger,\n });\n}\n\n/**\n * Update the Consent Manager to the latest airgap.js version\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateConsentManagerToLatest(\n client: GraphQLClient,\n options: {\n /** Consent manager to update */\n input: {\n /** ID of Consent Manager */\n id: string;\n /** Type of bundle */\n bundleType: ConsentBundleType;\n };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: consentManager, logger } = options;\n await makeGraphQLRequest(client, UPDATE_CONSENT_MANAGER_TO_LATEST, {\n variables: { airgapBundleId: consentManager.id, bundleType: consentManager.bundleType },\n logger,\n });\n}\n","import { gql } from 'graphql-request';\n\nexport const CONSENT_MANAGER_ANALYTICS_DATA = gql`\n query TranscendCliConsentManagerAnalyticsData($input: AnalyticsInput!) {\n analyticsData(input: $input) {\n series {\n name\n points {\n key\n value\n }\n }\n }\n }\n`;\n","import { gql } from 'graphql-request';\n\n// ---- Shared experience types ----\n\n/** Region associated with a consent experience */\nexport interface TranscendExperienceRegionGql {\n /** ISO country subdivision code */\n countrySubDivision?: string;\n /** ISO country code */\n country?: string;\n}\n\n/** Experience purpose reference */\nexport interface TranscendExperiencePurposeGql {\n /** Purpose display name */\n name: string;\n /** Purpose slug */\n trackingType: string;\n}\n\n/** Consent experience (regional regime) returned by EXPERIENCES query */\nexport interface TranscendExperienceGql {\n /** Experience ID */\n id: string;\n /** Internal name */\n name: string;\n /** Display name shown to users */\n displayName?: string;\n /** Regions where this experience applies */\n regions: TranscendExperienceRegionGql[];\n /** Whether regions list is inclusive or exclusive */\n operator: string;\n /** Display priority for ordering */\n displayPriority: number;\n /** Behavior on consent expiry */\n onConsentExpiry: string;\n /** Consent expiry duration */\n consentExpiry: number;\n /** Initial view state for auto-prompting */\n viewState: string;\n /** Purposes that can be opted out of */\n purposes: TranscendExperiencePurposeGql[];\n /** Purposes opted out by default */\n optedOutPurposes: TranscendExperiencePurposeGql[];\n /** Browser languages for this experience */\n browserLanguages: string[];\n /** Browser time zones for this experience */\n browserTimeZones: string[];\n}\n\n// ---- EXPERIENCES query ----\n\n/** Full response from the EXPERIENCES query */\nexport interface TranscendCliExperiencesResponse {\n /** Experiences result */\n experiences: {\n /** Total count of experiences */\n totalCount: number;\n /** List of experience nodes */\n nodes: TranscendExperienceGql[];\n };\n}\n\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const EXPERIENCES = gql`\n query TranscendCliExperiences($first: Int!, $offset: Int!) {\n experiences(first: $first, offset: $offset, useMaster: false) {\n totalCount\n nodes {\n id\n name\n displayName\n regions {\n countrySubDivision\n country\n }\n operator\n displayPriority\n onConsentExpiry\n consentExpiry\n viewState\n purposes {\n name\n trackingType\n }\n optedOutPurposes {\n name\n trackingType\n }\n browserLanguages\n browserTimeZones\n }\n }\n }\n`;\n\n// ---- UPDATE_CONSENT_EXPERIENCE mutation ----\n\n/** Full response from the UPDATE_CONSENT_EXPERIENCE mutation */\nexport interface TranscendCliUpdateConsentExperienceResponse {\n /** Mutation result */\n updateExperience: {\n /** Client mutation ID */\n clientMutationId: string | null;\n };\n}\n\nexport const UPDATE_CONSENT_EXPERIENCE = gql`\n mutation TranscendCliUpdateConsentExperience($input: UpdateExperienceInput!) {\n updateExperience(input: $input) {\n clientMutationId\n }\n }\n`;\n\n// ---- CREATE_CONSENT_EXPERIENCE mutation ----\n\n/** Full response from the CREATE_CONSENT_EXPERIENCE mutation */\nexport interface TranscendCliCreateConsentExperienceResponse {\n /** Mutation result */\n createExperience: {\n /** Client mutation ID */\n clientMutationId: string | null;\n };\n}\n\nexport const CREATE_CONSENT_EXPERIENCE = gql`\n mutation TranscendCliCreateConsentExperience($input: CreateExperienceInput!) {\n createExperience(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { InitialViewState, BrowserLanguage, OnConsentExpiry } from '@transcend-io/airgap.js-types';\nimport {\n ConsentPrecedenceOption,\n UnknownRequestPolicy,\n TelemetryPartitionStrategy,\n RegionsOperator,\n IsoCountrySubdivisionCode,\n IsoCountryCode,\n BrowserTimeZone,\n SignedIabAgreementOption,\n} from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport {\n FETCH_CONSENT_MANAGER_ID,\n FETCH_CONSENT_MANAGER,\n FETCH_CONSENT_MANAGER_THEME,\n type TranscendConsentManagerThemeGql,\n type TranscendCliFetchConsentManagerThemeResponse,\n} from './gqls/consentManager.js';\nimport { CONSENT_MANAGER_ANALYTICS_DATA } from './gqls/consentManagerMetrics.js';\nimport { EXPERIENCES } from './gqls/experiences.js';\n\nexport interface ConsentManager {\n /** ID of consent manager */\n id: string;\n /** Production bundle URL */\n bundleURL: string;\n /** Test bundle URL */\n testBundleURL: string;\n /** Configuration of consent manager */\n configuration: {\n /** Domain list */\n domains: string[];\n /** Consent precedence of user vs signal */\n consentPrecedence: ConsentPrecedenceOption;\n /** Unknown request policy */\n unknownRequestPolicy: UnknownRequestPolicy;\n /** Unknown cookie policy */\n unknownCookiePolicy: UnknownRequestPolicy;\n /** Sync endpoint */\n syncEndpoint: string;\n /** Telemetry partitioning */\n telemetryPartitioning: TelemetryPartitionStrategy;\n /** Signed IAB agreement */\n signedIabAgreement: SignedIabAgreementOption;\n /** Sync groups */\n syncGroups: string;\n /** Partition parameter */\n partition: string;\n };\n /** When using a custom partition, this is the partition value */\n partition?: {\n /** Partition value */\n partition: string;\n };\n}\n\n/**\n * Fetch consent manager\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Consent manager ID in organization\n */\nexport async function fetchConsentManager(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<ConsentManager> {\n const {\n consentManager: { consentManager },\n } = await makeGraphQLRequest<{\n /** Consent manager query */\n consentManager: {\n /** Consent manager object */\n consentManager: ConsentManager;\n };\n }>(client, FETCH_CONSENT_MANAGER, { logger: options.logger });\n return consentManager;\n}\n\n/**\n * Fetch consent manager ID\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Consent manager ID in organization\n */\nexport async function fetchConsentManagerId(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Max number of requests to send */\n maxRequests?: number;\n } = {},\n): Promise<string> {\n const {\n consentManager: { consentManager },\n } = await makeGraphQLRequest<{\n /** Consent manager query */\n consentManager: {\n /** Consent manager object */\n consentManager: {\n /** ID of bundle */\n id: string;\n };\n };\n }>(client, FETCH_CONSENT_MANAGER_ID, {\n logger: options.logger,\n maxRetries: options.maxRequests,\n });\n return consentManager.id;\n}\n\nconst PAGE_SIZE = 50;\n\nexport interface ConsentExperience {\n /** ID of experience */\n id: string;\n /** Name of experience */\n name: string;\n /** Experience display name */\n displayName?: string;\n /** Region that define this regional experience */\n regions: {\n /** Sub division */\n countrySubDivision?: IsoCountrySubdivisionCode;\n /** Country */\n country?: IsoCountryCode;\n }[];\n /** In vs not in operator */\n operator: RegionsOperator;\n /** Priority of experience */\n displayPriority: number;\n /** View state to prompt when auto prompting is enabled */\n viewState: InitialViewState;\n /** Consent expiry setting */\n onConsentExpiry: OnConsentExpiry;\n /** Consent expiry */\n consentExpiry: number;\n /** Purposes that can be opted out of in a particular experience */\n purposes: {\n /** Name of purpose */\n name: string;\n /** Purpose slug */\n trackingType: string;\n }[];\n /** Purposes that are opted out by default in a particular experience */\n optedOutPurposes: {\n /** Name of purpose */\n name: string;\n /** Purpose slug */\n trackingType: string;\n }[];\n /** Browser languages that define this regional experience */\n browserLanguages: BrowserLanguage[];\n /** Browser time zones that define this regional experience */\n browserTimeZones: BrowserTimeZone[];\n}\n\n/**\n * Fetch consent manager experiences\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Consent manager experiences in the organization\n */\nexport async function fetchConsentManagerExperiences(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<ConsentExperience[]> {\n const experiences: ConsentExperience[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n experiences: { nodes },\n } = await makeGraphQLRequest<{\n /** Consent experience */\n experiences: {\n /** List */\n nodes: ConsentExperience[];\n };\n }>(client, EXPERIENCES, {\n variables: { first: PAGE_SIZE, offset },\n logger: options.logger,\n });\n experiences.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return experiences.sort((a, b) => a.name.localeCompare(b.name));\n}\n\n/**\n * The allowed bin sizes for pulling consent metrics\n */\nexport enum ConsentManagerMetricBin {\n Hourly = '1h',\n Daily = '1d',\n}\n\nexport interface ConsentManagerMetric {\n /** Name of metric */\n name: string;\n /** The metrics */\n points: {\n /** Key of metric */\n key: string;\n /** Value of metric */\n value: string;\n }[];\n}\n\n/**\n * Fetch consent manager analytics data\n *\n * @param client - GraphQL client\n * @param input - Input for fetching data\n * @param options - Options\n * @returns Consent manager purposes in the organization\n */\nexport async function fetchConsentManagerAnalyticsData(\n client: GraphQLClient,\n input: {\n /** Data source */\n dataSource:\n | 'PRIVACY_SIGNAL_TIMESERIES'\n | 'CONSENT_CHANGES_TIMESERIES'\n | 'CONSENT_SESSIONS_BY_REGIME';\n /** Start date, in ISO string format */\n startDate: string;\n /** End date, in ISO string format */\n endDate: string;\n /** Force refetching */\n forceRefetch?: boolean;\n /** Airgap bundle ID */\n airgapBundleId: string;\n /** Bin interval */\n binInterval: ConsentManagerMetricBin;\n /** Whether or not to smooth the time series */\n smoothTimeseries: false;\n },\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<ConsentManagerMetric[]> {\n const {\n analyticsData: { series },\n } = await makeGraphQLRequest<{\n /** Analytics data response */\n analyticsData: {\n /** Consent manager metrics */\n series: ConsentManagerMetric[];\n };\n }>(client, CONSENT_MANAGER_ANALYTICS_DATA, {\n variables: { input },\n logger: options.logger,\n });\n return series;\n}\n\n/**\n * Fetch consent manager theme\n *\n * @param client - GraphQL client\n * @param airgapBundleId - Airgap bundle ID to fetch for\n * @param options - Options\n * @returns Consent manager ID in organization\n */\nexport async function fetchConsentManagerTheme(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy: {\n /** Airgap bundle ID to fetch for */\n airgapBundleId: string;\n };\n },\n): Promise<TranscendConsentManagerThemeGql> {\n const {\n consentManagerTheme: { theme },\n } = await makeGraphQLRequest<TranscendCliFetchConsentManagerThemeResponse>(\n client,\n FETCH_CONSENT_MANAGER_THEME,\n {\n variables: { airgapBundleId: options.filterBy.airgapBundleId },\n logger: options.logger,\n },\n );\n return theme;\n}\n","/** Service associated with a cookie or data flow */\nexport interface TranscendCookieServiceGql {\n /** Service ID */\n id: string;\n /** Human-readable service title */\n title: string;\n /** Integration slug */\n integrationName: string;\n}\n\n/** Service fields shared by cookies and data flows */\nexport const SERVICE_FIELDS = `\n id\n title\n integrationName\n`;\n\n/** Tracking purpose assigned to a cookie or data flow */\nexport interface TranscendTrackingPurposeGql {\n /** Purpose ID */\n id: string;\n /** Purpose display name */\n name: string;\n /** Purpose slug (e.g. \"Advertising\", \"Analytics\") */\n trackingType: string;\n}\n\n/** Tracking purpose fields */\nexport const TRACKING_PURPOSE_FIELDS = `\n id\n name\n trackingType\n`;\n","import type { ConsentTrackerSource, ConsentTrackerStatus } from '@transcend-io/privacy-types';\nimport { gql } from 'graphql-request';\n\nimport {\n ATTRIBUTE_VALUE_FIELDS,\n OWNER_FIELDS,\n TEAM_FIELDS,\n type TranscendAttributeValueGql,\n type TranscendOwnerGql,\n type TranscendTeamGql,\n} from '../../gqls/shared.js';\nimport {\n SERVICE_FIELDS,\n TRACKING_PURPOSE_FIELDS,\n type TranscendCookieServiceGql,\n type TranscendTrackingPurposeGql,\n} from './shared.js';\n\n// ---- Shared cookie types ----\n\n/** Cookie domain with occurrence count */\nexport interface TranscendCookieDomainGql {\n /** Domain ID */\n id: string;\n /** Domain name */\n domain: string;\n /** Number of occurrences on this domain */\n occurrences: number;\n}\n\n/** Cookie node returned by COOKIES query */\nexport interface TranscendCookieGql {\n /** Cookie ID */\n id: string;\n /** Cookie name */\n name: string;\n /** Whether this is a regex pattern */\n isRegex: boolean;\n /** Description */\n description?: string;\n /** Tracking purpose slugs (string array) */\n trackingPurposes: string[];\n /** Resolved tracking purposes */\n purposes: TranscendTrackingPurposeGql[];\n /** Frequency of occurrence (0-1) */\n frequency: number;\n /** Associated service */\n service?: TranscendCookieServiceGql;\n /** Whether marked as junk */\n isJunk: boolean;\n /** How the tracker was discovered */\n source: ConsentTrackerSource;\n /** Triage status */\n status: ConsentTrackerStatus;\n /** Assigned owners */\n owners: TranscendOwnerGql[];\n /** Assigned teams */\n teams: TranscendTeamGql[];\n /** Custom attribute values */\n attributeValues: TranscendAttributeValueGql[];\n /** Creation timestamp */\n createdAt: string;\n /** Last updated timestamp */\n updatedAt: string;\n /** Last seen by telemetry */\n lastDiscoveredAt?: string;\n /** Domains this cookie appears on */\n domains: TranscendCookieDomainGql[];\n /** Total telemetry occurrences */\n occurrences: number;\n /** Number of sites seen on (all time) */\n consentSiteCountAllTime: number;\n /** Number of sites seen on (last week) */\n consentSiteCountLastWeek: number;\n}\n\n/** Input for updating or creating a cookie */\nexport interface TranscendUpdateCookieInputGql {\n /** Cookie name (used as identifier for upsert) */\n name: string;\n /** Tracking purpose slugs */\n trackingPurposes?: string[];\n /** Purpose IDs to assign */\n purposeIds?: string[];\n /** Description */\n description?: string;\n /** Service integration name */\n service?: string;\n /** Mark as junk */\n isJunk?: boolean;\n /** Triage status */\n status?: ConsentTrackerStatus;\n /** Whether this is a regex pattern */\n isRegex?: boolean;\n /** How the tracker was discovered */\n source?: ConsentTrackerSource;\n}\n\n// ---- COOKIES query ----\n\n/** Full response from the COOKIES query */\nexport interface TranscendCliCookiesResponse {\n /** Cookies result */\n cookies: {\n /** List of cookie nodes */\n nodes: TranscendCookieGql[];\n /** Total count of matching cookies */\n totalCount: number;\n };\n}\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const COOKIES = gql`\n query TranscendCliCookies(\n $input: AirgapBundleInput!\n $first: Int!\n $offset: Int!\n $filterBy: CookiesFiltersInput\n $orderBy: [CookieOrder!]\n ) {\n cookies(\n input: $input\n first: $first\n offset: $offset\n filterBy: $filterBy\n orderBy: $orderBy\n useMaster: false\n ) {\n totalCount\n nodes {\n id\n name\n isRegex\n description\n trackingPurposes\n purposes { ${TRACKING_PURPOSE_FIELDS} }\n frequency\n service { ${SERVICE_FIELDS} }\n isJunk\n source\n status\n owners { ${OWNER_FIELDS} }\n teams { ${TEAM_FIELDS} }\n attributeValues { ${ATTRIBUTE_VALUE_FIELDS} }\n createdAt\n updatedAt\n lastDiscoveredAt\n domains {\n id\n domain\n occurrences\n }\n occurrences\n consentSiteCountAllTime\n consentSiteCountLastWeek\n }\n }\n }\n`;\n\n// ---- UPDATE_OR_CREATE_COOKIES mutation ----\n\n/** Full response from the UPDATE_OR_CREATE_COOKIES mutation */\nexport interface TranscendCliUpdateOrCreateCookiesResponse {\n /** Mutation result */\n updateOrCreateCookies: {\n /** Client mutation ID */\n clientMutationId: string | null;\n };\n}\n\nexport const UPDATE_OR_CREATE_COOKIES = gql`\n mutation TranscendCliUpdateOrCreateCookies(\n $cookies: [UpdateOrCreateCookieInput!]!\n $airgapBundleId: ID!\n ) {\n updateOrCreateCookies(input: { airgapBundleId: $airgapBundleId, cookies: $cookies }) {\n clientMutationId\n }\n }\n`;\n\n// ---- DELETE_COOKIES mutation ----\n\n/** Full response from the DELETE_COOKIES mutation */\nexport interface TranscendCliDeleteCookiesResponse {\n /** Mutation result */\n deleteCookies: {\n /** Client mutation ID */\n clientMutationId: string | null;\n };\n}\n\nexport const DELETE_COOKIES = gql`\n mutation TranscendCliDeleteCookies($input: DeleteCookiesInput!) {\n deleteCookies(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { ConsentTrackerStatus, OrderDirection } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { fetchConsentManagerId } from './fetchConsentManagerId.js';\nimport {\n COOKIES,\n type TranscendCookieGql,\n type TranscendCliCookiesResponse,\n} from './gqls/cookies.js';\n\n/** Sort order for cookie queries */\nexport interface CookieOrder {\n /** Field to sort by */\n field: string;\n /** Sort direction */\n direction: OrderDirection;\n}\n\nconst PAGE_SIZE = 20;\n\nconst DEFAULT_COOKIE_ORDER: CookieOrder[] = [\n { field: 'createdAt', direction: OrderDirection.Asc },\n { field: 'name', direction: OrderDirection.Asc },\n];\n\n/**\n * Fetch all Cookies in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All Cookies in the organization\n */\nexport async function fetchAllCookies(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** The status to fetch */\n status?: ConsentTrackerStatus;\n };\n /** Sort ordering (defaults to createdAt ASC, name ASC) */\n orderBy?: CookieOrder[];\n } = {},\n): Promise<TranscendCookieGql[]> {\n const {\n logger,\n filterBy: { status = ConsentTrackerStatus.Live } = {},\n orderBy = DEFAULT_COOKIE_ORDER,\n } = options;\n const cookies: TranscendCookieGql[] = [];\n let offset = 0;\n\n const airgapBundleId = await fetchConsentManagerId(client, { logger });\n\n let shouldContinue = false;\n do {\n const {\n cookies: { nodes },\n } = await makeGraphQLRequest<TranscendCliCookiesResponse>(client, COOKIES, {\n variables: {\n input: { airgapBundleId },\n first: PAGE_SIZE,\n offset,\n filterBy: { status },\n orderBy,\n },\n logger,\n });\n cookies.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return cookies.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import type {\n ConsentTrackerSource,\n ConsentTrackerStatus,\n DataFlowScope,\n} from '@transcend-io/privacy-types';\nimport { gql } from 'graphql-request';\n\nimport {\n ATTRIBUTE_VALUE_FIELDS,\n OWNER_FIELDS,\n TEAM_FIELDS,\n type TranscendAttributeValueGql,\n type TranscendOwnerGql,\n type TranscendTeamGql,\n} from '../../gqls/shared.js';\nimport {\n SERVICE_FIELDS,\n TRACKING_PURPOSE_FIELDS,\n type TranscendCookieServiceGql,\n type TranscendTrackingPurposeGql,\n} from './shared.js';\n\n// ---- Shared data flow types ----\n\n/** Data flow node returned by DATA_FLOWS query and UPDATE_DATA_FLOWS mutation */\nexport interface TranscendDataFlowGql {\n /** Data flow ID */\n id: string;\n /** URL/host value */\n value: string;\n /** Scope type (HOST, PATH, REGEX, etc.) */\n type: DataFlowScope;\n /** Description */\n description?: string;\n /** Tracking purpose slugs */\n trackingType: string[];\n /** Resolved tracking purposes */\n purposes: TranscendTrackingPurposeGql[];\n /** Frequency of occurrence (0-1) */\n frequency: number;\n /** Associated service */\n service?: TranscendCookieServiceGql;\n /** Whether marked as junk */\n isJunk: boolean;\n /** How the tracker was discovered */\n source: ConsentTrackerSource;\n /** Triage status */\n status: ConsentTrackerStatus;\n /** Assigned owners */\n owners: TranscendOwnerGql[];\n /** Assigned teams */\n teams: TranscendTeamGql[];\n /** Custom attribute values */\n attributeValues: TranscendAttributeValueGql[];\n /** Creation timestamp */\n createdAt: string;\n /** Last updated timestamp */\n updatedAt: string;\n /** Last seen by telemetry */\n lastDiscoveredAt?: string;\n /** Total telemetry occurrences */\n occurrences: number;\n /** Number of sites seen on (all time) */\n consentSiteCountAllTime: number;\n /** Number of sites seen on (last week) */\n consentSiteCountLastWeek: number;\n}\n\n/** Input for updating a data flow */\nexport interface TranscendUpdateDataFlowInputGql {\n /** Data flow ID */\n id: string;\n /** URL/host value */\n value?: string;\n /** Scope type */\n type?: DataFlowScope;\n /** Tracking purpose slugs */\n trackingType?: string[];\n /** Purpose IDs to assign */\n purposeIds?: string[];\n /** Description */\n description?: string;\n /** Service integration name */\n service?: string;\n /** Mark as junk */\n isJunk?: boolean;\n /** Triage status */\n status?: ConsentTrackerStatus;\n}\n\n// ---- Shared field selection for mutation responses ----\n\nconst DATA_FLOW_RESPONSE_FIELDS = `\n id\n value\n type\n description\n trackingType\n purposes { ${TRACKING_PURPOSE_FIELDS} }\n frequency\n service { ${SERVICE_FIELDS} }\n isJunk\n source\n status\n createdAt\n updatedAt\n lastDiscoveredAt\n occurrences\n consentSiteCountAllTime\n consentSiteCountLastWeek\n`;\n\n// ---- CREATE_DATA_FLOWS mutation ----\n\n/** Full response from the CREATE_DATA_FLOWS mutation */\nexport interface TranscendCliCreateDataFlowsResponse {\n /** Mutation result */\n createDataFlows: {\n /** Created data flows (IDs only) */\n dataFlows: {\n /** Data flow ID */\n id: string;\n }[];\n };\n}\n\nexport const CREATE_DATA_FLOWS = gql`\n mutation TranscendCliCreateDataFlows(\n $dataFlows: [DataFlowInput!]!\n $airgapBundleId: ID!\n $classifyService: Boolean\n ) {\n createDataFlows(\n input: {\n airgapBundleId: $airgapBundleId\n dataFlows: $dataFlows\n classifyService: $classifyService\n }\n ) {\n dataFlows {\n id\n }\n }\n }\n`;\n\n// ---- UPDATE_DATA_FLOWS mutation ----\n\n/** Full response from the UPDATE_DATA_FLOWS mutation */\nexport interface TranscendCliUpdateDataFlowsResponse {\n /** Mutation result */\n updateDataFlows: {\n /** Updated data flows with full fields */\n dataFlows: TranscendDataFlowGql[];\n };\n}\n\nexport const UPDATE_DATA_FLOWS = gql`\n mutation TranscendCliUpdateDataFlows(\n $airgapBundleId: ID!\n $dataFlows: [UpdateDataFlowInput!]!\n $classifyService: Boolean\n ) {\n updateDataFlows(\n input: {\n airgapBundleId: $airgapBundleId\n dataFlows: $dataFlows\n classifyService: $classifyService\n }\n ) {\n dataFlows { ${DATA_FLOW_RESPONSE_FIELDS} }\n }\n }\n`;\n\n// ---- DATA_FLOWS query ----\n\n/** Full response from the DATA_FLOWS query */\nexport interface TranscendCliDataFlowsResponse {\n /** Data flows result */\n dataFlows: {\n /** List of data flow nodes */\n nodes: TranscendDataFlowGql[];\n /** Total count of matching data flows */\n totalCount: number;\n };\n}\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_FLOWS = gql`\n query TranscendCliDataFlows(\n $input: AirgapBundleInput!\n $first: Int!\n $offset: Int!\n $filterBy: DataFlowsFiltersInput\n $orderBy: [DataFlowOrder!]\n ) {\n dataFlows(\n input: $input\n first: $first\n offset: $offset\n filterBy: $filterBy\n orderBy: $orderBy\n useMaster: false\n ) {\n totalCount\n nodes {\n id\n value\n type\n description\n trackingType\n purposes { ${TRACKING_PURPOSE_FIELDS} }\n frequency\n service { ${SERVICE_FIELDS} }\n isJunk\n source\n status\n owners { ${OWNER_FIELDS} }\n teams { ${TEAM_FIELDS} }\n attributeValues { ${ATTRIBUTE_VALUE_FIELDS} }\n createdAt\n updatedAt\n lastDiscoveredAt\n occurrences\n consentSiteCountAllTime\n consentSiteCountLastWeek\n }\n }\n }\n`;\n\n// ---- DELETE_DATA_FLOWS mutation ----\n\n/** Full response from the DELETE_DATA_FLOWS mutation */\nexport interface TranscendCliDeleteDataFlowsResponse {\n /** Mutation result */\n deleteDataFlows: {\n /** Client mutation ID */\n clientMutationId: string | null;\n };\n}\n\nexport const DELETE_DATA_FLOWS = gql`\n mutation TranscendCliDeleteDataFlows($input: DeleteDataFlowsInput!) {\n deleteDataFlows(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { ConsentTrackerStatus, OrderDirection } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { fetchConsentManagerId } from './fetchConsentManagerId.js';\nimport {\n DATA_FLOWS,\n type TranscendDataFlowGql,\n type TranscendCliDataFlowsResponse,\n} from './gqls/dataFlows.js';\n\n/** Sort order for data flow queries */\nexport interface DataFlowOrder {\n /** Field to sort by */\n field: string;\n /** Sort direction */\n direction: OrderDirection;\n}\n\nconst PAGE_SIZE = 20;\n\nconst DEFAULT_DATA_FLOW_ORDER: DataFlowOrder[] = [\n { field: 'createdAt', direction: OrderDirection.Asc },\n { field: 'value', direction: OrderDirection.Asc },\n];\n\n/**\n * Fetch all DataFlows in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All DataFlows in the organization\n */\nexport async function fetchAllDataFlows(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** The status to fetch */\n status?: ConsentTrackerStatus;\n };\n /** Sort ordering (defaults to createdAt ASC, value ASC) */\n orderBy?: DataFlowOrder[];\n } = {},\n): Promise<TranscendDataFlowGql[]> {\n const {\n logger,\n filterBy: { status = ConsentTrackerStatus.Live } = {},\n orderBy = DEFAULT_DATA_FLOW_ORDER,\n } = options;\n const dataFlows: TranscendDataFlowGql[] = [];\n let offset = 0;\n\n const airgapBundleId = await fetchConsentManagerId(client, { logger });\n\n let shouldContinue = false;\n do {\n const {\n dataFlows: { nodes },\n } = await makeGraphQLRequest<TranscendCliDataFlowsResponse>(client, DATA_FLOWS, {\n variables: {\n input: { airgapBundleId },\n first: PAGE_SIZE,\n offset,\n filterBy: {\n status,\n ...(status === ConsentTrackerStatus.NeedsReview ? { showZeroActivity: true } : {}),\n },\n orderBy,\n },\n logger,\n });\n dataFlows.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return dataFlows.sort((a, b) => a.value.localeCompare(b.value));\n}\n","import { gql } from 'graphql-request';\n\nexport const FETCH_PRIVACY_CENTER_ID = gql`\n query TranscendCliFetchPrivacyCenterId($url: String!) {\n privacyCenter(lookup: { url: $url }) {\n id\n }\n }\n`;\n\nexport const DEPLOYED_PRIVACY_CENTER_URL = gql`\n query TranscendCliDeployedPrivacyCenterUrl {\n organization {\n deployedPrivacyCenterUrl\n }\n }\n`;\n\nexport const PRIVACY_CENTER = gql`\n query TranscendCliFetchPrivacyCenters($url: String!) {\n privacyCenter(lookup: { url: $url }) {\n id\n url\n isDisabled\n showPrivacyRequestButton\n showPolicies\n showTrackingTechnologies\n showCookies\n showDataFlows\n showConsentManager\n showManageYourPrivacy\n showMarketingPreferences\n locales\n defaultLocale\n preferBrowserDefaultLocale\n supportEmail\n replyToEmail\n useNoReplyEmailAddress\n useCustomEmailDomain\n transformAccessReportJsonToCsv\n themeStr\n }\n }\n`;\n\nexport const UPDATE_PRIVACY_CENTER = gql`\n mutation TranscendCliUpdatePrivacyCenter($input: UpdatePrivacyCenterInput!) {\n updatePrivacyCenter(input: $input) {\n clientMutationId\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { DEPLOYED_PRIVACY_CENTER_URL, FETCH_PRIVACY_CENTER_ID } from './gqls/privacyCenter.js';\n\n/**\n * Fetch default privacy center URL\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Privacy center URL in organization\n */\nexport async function fetchPrivacyCenterUrl(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<string> {\n const { organization } = await makeGraphQLRequest<{\n /** Organization */\n organization: {\n /** URL */\n deployedPrivacyCenterUrl: string;\n };\n }>(client, DEPLOYED_PRIVACY_CENTER_URL, { logger: options.logger });\n return organization.deployedPrivacyCenterUrl;\n}\n\n/**\n * Fetch privacy center ID\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Privacy center ID in organization\n */\nexport async function fetchPrivacyCenterId(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** URL to look up */\n url?: string;\n };\n } = {},\n): Promise<string> {\n const { logger, filterBy: { url } = {} } = options;\n let urlToUse = url;\n if (!urlToUse) {\n urlToUse = await fetchPrivacyCenterUrl(client, { logger });\n }\n const { privacyCenter } = await makeGraphQLRequest<{\n /** Privacy center query */\n privacyCenter: {\n /** ID of bundle */\n id: string;\n };\n }>(client, FETCH_PRIVACY_CENTER_ID, {\n variables: { url: urlToUse },\n logger,\n });\n return privacyCenter.id;\n}\n","import { gql } from 'graphql-request';\n\nexport const POLICIES = gql`\n query TranscendCliFetchPolicies($url: String!) {\n privacyCenterPolicies(lookup: { url: $url }) {\n id\n title {\n defaultMessage\n }\n disableEffectiveOn\n disabledLocales\n versions {\n effectiveOn\n content {\n defaultMessage\n }\n }\n }\n }\n`;\n\nexport const UPDATE_POLICIES = gql`\n mutation TranscendCliUpdatePolicies($policies: [PolicyInput!]!, $privacyCenterId: ID!) {\n updatePolicies(\n input: { privacyCenterId: $privacyCenterId, policies: $policies, skipPublish: true }\n ) {\n clientMutationId\n }\n }\n`;\n","import type { LocaleValue } from '@transcend-io/internationalization';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { fetchPrivacyCenterUrl } from './fetchPrivacyCenterId.js';\nimport { POLICIES } from './gqls/policy.js';\n\nexport interface Policy {\n /** ID of policy */\n id: string;\n /** Title of policy */\n title: {\n /** Default message */\n defaultMessage: string;\n };\n /** Disabled locales */\n disabledLocales: LocaleValue[];\n /** Versions */\n versions: {\n /** Message content */\n content: {\n /** Default message */\n defaultMessage: string;\n };\n }[];\n}\n\n/**\n * Fetch all policies in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All policies in the organization\n */\nexport async function fetchAllPolicies(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Policy[]> {\n const { logger } = options;\n const deployedPrivacyCenterUrl = await fetchPrivacyCenterUrl(client, { logger });\n const { privacyCenterPolicies } = await makeGraphQLRequest<{\n /** Policies */\n privacyCenterPolicies: Policy[];\n }>(client, POLICIES, {\n variables: { url: deployedPrivacyCenterUrl },\n logger,\n });\n\n return privacyCenterPolicies.sort((a, b) =>\n a.title.defaultMessage.localeCompare(b.title.defaultMessage),\n );\n}\n","import type { LocaleValue } from '@transcend-io/internationalization';\nimport { PrivacyCenterThemePartial } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { fetchPrivacyCenterUrl } from './fetchPrivacyCenterId.js';\nimport { PRIVACY_CENTER } from './gqls/privacyCenter.js';\n\nexport interface PrivacyCenter {\n /** ID of the privacy center */\n id: string;\n /** The URL of the privacy center */\n url: string;\n /** Whether or not the entire privacy center is enabled or disabled */\n isDisabled: boolean;\n /** Whether or not to show the privacy requests button */\n showPrivacyRequestButton: boolean;\n /** Whether or not to show the policies page */\n showPolicies: boolean;\n /** Whether or not to show the tracking technologies page */\n showTrackingTechnologies: boolean;\n /** Whether or not to show the cookies on the tracking technologies page */\n showCookies: boolean;\n /** Whether or not to show the data flows on the tracking technologies page */\n showDataFlows: boolean;\n /** Whether or not to show the consent manager opt out options on the tracking technologies page */\n showConsentManager: boolean;\n /** Whether or not to show the manage your privacy page */\n showManageYourPrivacy: boolean;\n /** Whether or not to show the marketing preferences page */\n showMarketingPreferences: boolean;\n /** What languages are supported for the privacy center */\n locales: LocaleValue[];\n /** The default locale for the privacy center */\n defaultLocale: LocaleValue;\n /** Whether or not to prefer the browser default locale */\n preferBrowserDefaultLocale: boolean;\n /** The email addresses of the employees within your company that are the go-to individuals for managing this privacy center */\n supportEmail: string;\n /** The email addresses of the employees within your company that are the go-to individuals for managing this privacy center */\n replyToEmail: string;\n /** Whether or not to send emails from a no reply email */\n useNoReplyEmailAddress: boolean;\n /** Whether or not to use a custom email domain */\n useCustomEmailDomain: boolean;\n /** Whether or not to transcend access requests from JSON to CSV */\n transformAccessReportJsonToCsv: boolean;\n /** The theme object of colors to display on the privacy center */\n theme: PrivacyCenterThemePartial;\n}\n\n/**\n * Fetch all privacy centers in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All privacy centers in the organization\n */\nexport async function fetchAllPrivacyCenters(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<PrivacyCenter[]> {\n const { logger } = options;\n const deployedPrivacyCenterUrl = await fetchPrivacyCenterUrl(client, { logger });\n const {\n privacyCenter: { themeStr, ...rest },\n } = await makeGraphQLRequest<{\n /** Privacy centers */\n privacyCenter: Omit<PrivacyCenter, 'theme'> & {\n /** Theme string */\n themeStr: string;\n };\n }>(client, PRIVACY_CENTER, {\n variables: { url: deployedPrivacyCenterUrl },\n logger,\n });\n\n return [\n {\n ...rest,\n theme: JSON.parse(themeStr),\n },\n ];\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// orderBy: [\n// { field: createdAt, direction: ASC }\n// { field: name, direction: ASC }\n// ]\nexport const PROCESSING_PURPOSE_SUB_CATEGORIES = gql`\n query TranscendCliProcessingPurposeSubCategories($first: Int!, $offset: Int!) {\n processingPurposeSubCategories(\n first: $first\n offset: $offset\n isExportCsv: true\n useMaster: false\n ) {\n nodes {\n id\n name\n purpose\n description\n teams {\n name\n }\n owners {\n email\n }\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n }\n }\n }\n`;\n\nexport const CREATE_PROCESSING_PURPOSE_SUB_CATEGORY = gql`\n mutation TranscendCliCreateProcessingPurposeSubCategory(\n $input: CreateProcessingPurposeCategoryInput!\n ) {\n createProcessingPurposeSubCategory(input: $input) {\n processingPurposeSubCategory {\n id\n name\n purpose\n }\n }\n }\n`;\n\nexport const UPDATE_PROCESSING_PURPOSE_SUB_CATEGORIES = gql`\n mutation TranscendCliUpdateProcessingPurposeSubCategories(\n $input: UpdateProcessingPurposeSubCategoriesInput!\n ) {\n updateProcessingPurposeSubCategories(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { ProcessingPurpose } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PROCESSING_PURPOSE_SUB_CATEGORIES } from './gqls/processingPurpose.js';\n\nexport interface ProcessingPurposeSubCategory {\n /** ID of processing purpose */\n id: string;\n /** Name of processing purpose */\n name: string;\n /** Type of processing purpose */\n purpose: ProcessingPurpose;\n /** Description of processing purpose */\n description?: string;\n /** Assigned teams */\n teams: {\n /** Team name */\n name: string;\n }[];\n /** Assigned owners */\n owners: {\n /** Email */\n email: string;\n }[];\n /** Custom fields */\n attributeValues: {\n /** Name of attribute value */\n name: string;\n /** Attribute key that the value represents */\n attributeKey: {\n /** Name of attribute team */\n name: string;\n };\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all processingPurposeSubCategories in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All processingPurposeSubCategories in the organization\n */\nexport async function fetchAllProcessingPurposes(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<ProcessingPurposeSubCategory[]> {\n const processingPurposeSubCategories: ProcessingPurposeSubCategory[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n processingPurposeSubCategories: { nodes },\n } = await makeGraphQLRequest<{\n /** DataCategories */\n processingPurposeSubCategories: {\n /** List */\n nodes: ProcessingPurposeSubCategory[];\n };\n }>(client, PROCESSING_PURPOSE_SUB_CATEGORIES, {\n variables: { first: PAGE_SIZE, offset },\n logger: options.logger,\n });\n processingPurposeSubCategories.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return processingPurposeSubCategories.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n/** Preference topic title translation */\nexport interface TranscendPreferenceTopicTitle {\n /** Translated description */\n description: string;\n}\n\n/** Preference topic linked to a purpose */\nexport interface TranscendPreferenceTopicGql {\n /** Topic ID */\n id: string;\n /** Topic slug */\n slug: string;\n /** Topic title with translations */\n title: TranscendPreferenceTopicTitle;\n /** Display color */\n color: string;\n}\n\n/** Data silo (integration) mapped to a purpose */\nexport interface TranscendMappedDataSiloGql {\n /** Data silo ID */\n id: string;\n /** Data silo display title */\n title: string;\n /** Data silo type */\n type: string;\n}\n\n/** Tracking purpose returned by the PURPOSES query */\nexport interface TranscendPurposeGql {\n /** Purpose ID */\n id: string;\n /** Purpose display name */\n name: string;\n /** Purpose description */\n description: string | null;\n /** Default consent state */\n defaultConsent: string;\n /** Purpose slug */\n trackingType: string;\n /** Whether the purpose is user-configurable */\n configurable: boolean;\n /** Whether the purpose is essential (non-optional) */\n essential: boolean;\n /** Whether the purpose appears in the consent manager UI */\n showInConsentManager: boolean;\n /** Whether the purpose is currently active */\n isActive: boolean;\n /** Display ordering weight */\n displayOrder: number;\n /** Signals that trigger automatic opt-out (e.g. GPC) */\n optOutSignals: string[];\n /** Soft-deletion timestamp, null if active */\n deletedAt: string | null;\n /** Authentication level required */\n authLevel: string;\n /** Whether the purpose appears in the privacy center */\n showInPrivacyCenter: boolean;\n /** Localized display title */\n title: string | null;\n /** Linked preference topics */\n preferenceTopics: TranscendPreferenceTopicGql[];\n /** Number of data points tracked under this purpose */\n purposeDataPointCount: number;\n /** Number of preference topic option value data points */\n preferenceTopicOptionValueDataPointCount: number;\n /** Data silos mapped to this purpose */\n mappedDataSilos: TranscendMappedDataSiloGql[];\n}\n\n/** Full response from the PURPOSES query */\nexport interface TranscendCliPurposesResponse {\n /** Purposes result */\n purposes: {\n /** List of purpose nodes */\n nodes: TranscendPurposeGql[];\n /** Total count of purposes */\n totalCount: number;\n };\n}\n\nexport const PURPOSES = gql`\n query TranscendCliPurposes($first: Int!) {\n purposes(first: $first) {\n nodes {\n id\n name\n description\n defaultConsent\n trackingType\n configurable\n essential\n showInConsentManager\n isActive\n displayOrder\n optOutSignals\n deletedAt\n authLevel\n showInPrivacyCenter\n title\n preferenceTopics {\n id\n slug\n title {\n description\n }\n color\n }\n purposeDataPointCount\n preferenceTopicOptionValueDataPointCount\n mappedDataSilos {\n id\n title\n type\n }\n }\n totalCount\n }\n }\n`;\n","import { gql } from 'graphql-request';\n\n// ---- Shared partition types ----\n\n/** Consent partition node */\nexport interface TranscendConsentPartitionGql {\n /** Partition ID */\n id: string;\n /** Partition name */\n name: string;\n /** Partition key */\n partition: string;\n}\n\n// ---- CONSENT_PARTITIONS query ----\n\n/** Full response from the CONSENT_PARTITIONS query */\nexport interface TranscendCliConsentPartitionsResponse {\n /** Partitions result */\n consentPartitions: {\n /** List of partition nodes */\n nodes: TranscendConsentPartitionGql[];\n };\n}\n\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// useMaster: false\n// isExportCsv: true\nexport const CONSENT_PARTITIONS = gql`\n query TranscendCliConsentPartitions($first: Int!, $offset: Int!) {\n consentPartitions(first: $first, offset: $offset) {\n nodes {\n id\n name\n partition\n }\n }\n }\n`;\n\n// ---- CREATE_CONSENT_PARTITION mutation ----\n\n/** Full response from the CREATE_CONSENT_PARTITION mutation */\nexport interface TranscendCliCreateConsentPartitionResponse {\n /** Mutation result */\n createConsentPartition: {\n /** Client mutation ID */\n clientMutationId: string | null;\n };\n}\n\nexport const CREATE_CONSENT_PARTITION = gql`\n mutation TranscendCliCreateConsentPartition($input: CreateConsentPartitionInput!) {\n createConsentPartition(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { gql } from 'graphql-request';\n\n/** Stats counts returned by COOKIE_STATS and DATA_FLOW_STATS */\nexport interface TranscendTrackerStatsGql {\n /** Number of live (approved) items */\n liveCount: number;\n /** Number of items needing review */\n needReviewCount: number;\n /** Number of junked items */\n junkCount: number;\n}\n\n/** Full response from the COOKIE_STATS query */\nexport interface TranscendCliCookieStatsResponse {\n /** Cookie stats result */\n cookieStats: TranscendTrackerStatsGql;\n}\n\nexport const COOKIE_STATS = gql`\n query TranscendCliCookieStats($input: AirgapBundleInput!) {\n cookieStats(input: $input) {\n liveCount\n needReviewCount\n junkCount\n }\n }\n`;\n\n/** Full response from the DATA_FLOW_STATS query */\nexport interface TranscendCliDataFlowStatsResponse {\n /** Data flow stats result */\n dataFlowStats: TranscendTrackerStatsGql;\n}\n\nexport const DATA_FLOW_STATS = gql`\n query TranscendCliDataFlowStats($input: AirgapBundleInput!) {\n dataFlowStats(input: $input) {\n liveCount\n needReviewCount\n junkCount\n }\n }\n`;\n","import { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { difference } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchConsentManagerId } from './fetchConsentManagerId.js';\nimport {\n CONSENT_PARTITIONS,\n CREATE_CONSENT_PARTITION,\n type TranscendConsentPartitionGql,\n type TranscendCliConsentPartitionsResponse,\n} from './gqls/partitions.js';\n\nconst PAGE_SIZE = 50;\n\nexport interface PartitionInput {\n /** Name of partition */\n name: string;\n /** Value of partition, cannot be pushed, can only be pulled */\n partition?: string;\n}\n\n/**\n * Fetch the list of partitions\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Partition list\n */\nexport async function fetchPartitions(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<TranscendConsentPartitionGql[]> {\n const { logger = NOOP_LOGGER } = options;\n const partitions: TranscendConsentPartitionGql[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n consentPartitions: { nodes },\n } = await makeGraphQLRequest<TranscendCliConsentPartitionsResponse>(\n client,\n CONSENT_PARTITIONS,\n {\n variables: { first: PAGE_SIZE, offset },\n logger,\n },\n );\n partitions.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return partitions.sort((a, b) => a.name.localeCompare(b.name));\n}\n\n/**\n * Sync the consent partitions\n *\n * @param client - GraphQL client\n * @param partitionInputs - The partition inputs\n * @param options - Options\n * @returns True on success\n */\nexport async function syncPartitions(\n client: GraphQLClient,\n partitionInputs: PartitionInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n const airgapBundleId = await fetchConsentManagerId(client, { logger });\n let encounteredError = false;\n const partitions = await fetchPartitions(client, { logger });\n const newPartitionNames = difference(\n partitionInputs.map(({ name }) => name),\n partitions.map(({ name }) => name),\n );\n await mapSeries(newPartitionNames, async (name) => {\n try {\n await makeGraphQLRequest(client, CREATE_CONSENT_PARTITION, {\n variables: {\n input: {\n id: airgapBundleId,\n name,\n },\n },\n logger,\n });\n logger.info(`Successfully created consent partition: ${name}!`);\n } catch (err) {\n logger.error(`Failed to create consent partition: ${name}! - ${(err as Error).message}`);\n encounteredError = true;\n }\n });\n return !encounteredError;\n}\n","import { InitialViewState, OnConsentExpiry, BrowserLanguage } from '@transcend-io/airgap.js-types';\nimport {\n ConsentBundleType,\n ConsentPrecedenceOption,\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n RegionsOperator,\n UnknownRequestPolicy,\n TelemetryPartitionStrategy,\n SignedIabAgreementOption,\n BrowserTimeZone,\n} from '@transcend-io/privacy-types';\nimport { map, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllPurposes } from '../preference-management/fetchAllPurposes.js';\nimport { fetchConsentManagerId, fetchConsentManagerExperiences } from './fetchConsentManagerId.js';\nimport { fetchPrivacyCenterId } from './fetchPrivacyCenterId.js';\nimport {\n UPDATE_CONSENT_MANAGER_DOMAINS,\n CREATE_CONSENT_MANAGER,\n UPDATE_LOAD_OPTIONS,\n UPDATE_CONSENT_MANAGER_PARTITION,\n UPDATE_CONSENT_MANAGER_VERSION,\n TOGGLE_TELEMETRY_PARTITION_STRATEGY,\n TOGGLE_UNKNOWN_COOKIE_POLICY,\n TOGGLE_CONSENT_PRECEDENCE,\n TOGGLE_UNKNOWN_REQUEST_POLICY,\n UPDATE_CONSENT_MANAGER_THEME,\n} from './gqls/consentManager.js';\nimport { UPDATE_CONSENT_EXPERIENCE, CREATE_CONSENT_EXPERIENCE } from './gqls/experiences.js';\nimport { fetchPartitions } from './syncPartitions.js';\n\nconst PURPOSES_LINK = 'https://app.transcend.io/consent-manager/regional-experiences/purposes';\n\nexport interface ConsentManageExperienceInput {\n /** Name of experience */\n name: string;\n /** Display name of experience */\n displayName?: string;\n /** Regions that define this regional experience */\n regions?: {\n /** Country */\n country?: IsoCountryCode;\n /** Country subdivision */\n countrySubDivision?: IsoCountrySubdivisionCode;\n }[];\n /** How to handle consent expiry */\n onConsentExpiry?: OnConsentExpiry;\n /** Consent expiration value */\n consentExpiry?: number;\n /** In vs not in operator */\n operator?: RegionsOperator;\n /** Priority of experience */\n displayPriority?: number;\n /** View state to prompt when auto prompting is enabled */\n viewState?: InitialViewState;\n /** Purposes that can be opted out of in a particular experience */\n purposes?: {\n /** Slug of purpose */\n trackingType: string;\n }[];\n /** Purposes that are opted out by default in a particular experience */\n optedOutPurposes?: {\n /** Slug of purpose */\n trackingType: string;\n }[];\n /** Browser languages that define this regional experience */\n browserLanguages?: BrowserLanguage[];\n /** Browser time zones that define this regional experience */\n browserTimeZones?: BrowserTimeZone[];\n}\n\nexport interface ConsentManagerInput {\n /** Airgap version */\n version?: string;\n /** Bundle URLs per bundle type */\n bundleUrls?: Partial<Record<ConsentBundleType, string>>;\n /** The consent manager domains */\n domains?: string[];\n /** Key used to partition consent records */\n partition?: string;\n /** Precedence of signals vs user input */\n consentPrecedence?: ConsentPrecedenceOption;\n /** The consent manager unknown request policy */\n unknownRequestPolicy?: UnknownRequestPolicy;\n /** The consent manager unknown cookie policy */\n unknownCookiePolicy?: UnknownRequestPolicy;\n /** The XDI sync endpoint */\n syncEndpoint?: string;\n /** The telemetry partitioning strategy */\n telemetryPartitioning?: TelemetryPartitionStrategy;\n /** Whether the site owner has signed the IAB agreement */\n signedIabAgreement?: SignedIabAgreementOption;\n /** Regional experience configurations */\n experiences?: ConsentManageExperienceInput[];\n /** Theme configuration */\n theme?: {\n /** Primary color */\n primaryColor?: string;\n /** Font color */\n fontColor?: string;\n /** Privacy policy URL */\n privacyPolicy?: string;\n /** Auto-prompt setting */\n prompt?: number;\n };\n /** The Shared XDI host sync groups config (JSON) */\n syncGroups?: string;\n}\n\n/**\n * Sync consent manager experiences up to Transcend\n *\n * @param client - GraphQL client\n * @param experiences - The experience inputs\n * @param options - Options\n */\nexport async function syncConsentManagerExperiences(\n client: GraphQLClient,\n experiences: ConsentManageExperienceInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n const { logger = NOOP_LOGGER } = options;\n\n const existingExperiences = await fetchConsentManagerExperiences(client, {\n logger,\n });\n const experienceLookup = keyBy(existingExperiences, 'name');\n\n const purposes = await fetchAllPurposes(client, { logger });\n const purposeLookup = keyBy(purposes, 'trackingType');\n\n await map(\n experiences,\n async (exp, ind) => {\n const purposeIds = exp.purposes?.map((purpose, ind2) => {\n const existingPurpose = purposeLookup[purpose.trackingType];\n if (!existingPurpose) {\n throw new Error(\n `Invalid purpose trackingType provided at consentManager.experiences[${ind}].purposes[${ind2}]: ` +\n `${purpose.trackingType}. See list of valid purposes ${PURPOSES_LINK}`,\n );\n }\n return existingPurpose.id;\n });\n const optedOutPurposeIds = exp.optedOutPurposes?.map((purpose, ind2) => {\n const existingPurpose = purposeLookup[purpose.trackingType];\n if (!existingPurpose) {\n throw new Error(\n `Invalid purpose trackingType provided at consentManager.experiences[${ind}].optedOutPurposes[${ind2}]: ` +\n `${purpose.trackingType}. See list of valid purposes ${PURPOSES_LINK}`,\n );\n }\n return existingPurpose.id;\n });\n\n const existingExperience = experienceLookup[exp.name];\n if (existingExperience) {\n await makeGraphQLRequest(client, UPDATE_CONSENT_EXPERIENCE, {\n variables: {\n input: {\n id: existingExperience.id,\n name: exp.displayName,\n regions: exp.regions,\n operator: exp.operator,\n onConsentExpiry: exp.onConsentExpiry,\n consentExpiry: exp.consentExpiry,\n displayPriority:\n exp.displayPriority !== existingExperience.displayPriority\n ? exp.displayPriority\n : undefined,\n viewState: exp.viewState,\n purposes: purposeIds,\n optedOutPurposes: optedOutPurposeIds,\n browserLanguages: exp.browserLanguages,\n browserTimeZones: exp.browserTimeZones,\n },\n },\n logger,\n });\n logger.info(`Successfully synced consent experience \"${exp.name}\"!`);\n } else {\n await makeGraphQLRequest(client, CREATE_CONSENT_EXPERIENCE, {\n variables: {\n input: {\n name: exp.name,\n displayName: exp.displayName,\n regions: exp.regions,\n operator: exp.operator,\n onConsentExpiry: exp.onConsentExpiry || OnConsentExpiry.Prompt,\n consentExpiry: exp.consentExpiry,\n displayPriority: exp.displayPriority,\n viewState: exp.viewState || InitialViewState.Hidden,\n purposes: purposeIds || [],\n optedOutPurposes: optedOutPurposeIds || [],\n browserLanguages: exp.browserLanguages,\n browserTimeZones: exp.browserTimeZones,\n },\n },\n logger,\n });\n logger.info(`Successfully created consent experience \"${exp.name}\"!`);\n }\n },\n {\n concurrency: 10,\n },\n );\n}\n\n/**\n * Sync the consent manager\n *\n * @param client - GraphQL client\n * @param consentManager - The consent manager input\n * @param options - Options\n */\nexport async function syncConsentManager(\n client: GraphQLClient,\n consentManager: ConsentManagerInput,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n const { logger = NOOP_LOGGER } = options;\n let airgapBundleId: string;\n\n try {\n airgapBundleId = await fetchConsentManagerId(client, {\n logger,\n maxRequests: 1,\n });\n } catch (err) {\n // TODO: https://transcend.height.app/T-23778\n if ((err as Error).message.includes('AirgapBundle not found')) {\n const privacyCenterId = await fetchPrivacyCenterId(client, {\n logger,\n });\n\n const { createConsentManager } = await makeGraphQLRequest<{\n /** Create consent manager */\n createConsentManager: {\n /** Consent manager */\n consentManager: {\n /** ID */\n id: string;\n };\n };\n }>(client, CREATE_CONSENT_MANAGER, {\n variables: { privacyCenterId },\n logger,\n });\n airgapBundleId = createConsentManager.consentManager.id;\n } else {\n throw err;\n }\n }\n\n if (consentManager.domains) {\n await makeGraphQLRequest(client, UPDATE_CONSENT_MANAGER_DOMAINS, {\n variables: { domains: consentManager.domains, airgapBundleId },\n logger,\n });\n }\n\n if (consentManager.partition) {\n const partitions = await fetchPartitions(client, { logger });\n const partitionToUpdate = partitions.find((part) => part.name === consentManager.partition);\n if (!partitionToUpdate) {\n throw new Error(\n `Partition \"${consentManager.partition}\" not found. Please create the partition first.`,\n );\n }\n await makeGraphQLRequest(client, UPDATE_CONSENT_MANAGER_PARTITION, {\n variables: { partitionId: partitionToUpdate.id, airgapBundleId },\n logger,\n });\n }\n\n if (consentManager.version) {\n await makeGraphQLRequest(client, UPDATE_CONSENT_MANAGER_VERSION, {\n variables: { airgapBundleId, version: consentManager.version },\n logger,\n });\n }\n\n if (consentManager.signedIabAgreement) {\n await makeGraphQLRequest(client, UPDATE_LOAD_OPTIONS, {\n variables: {\n input: {\n id: airgapBundleId,\n ...(consentManager.signedIabAgreement\n ? { signedIabAgreement: consentManager.signedIabAgreement }\n : {}),\n },\n },\n logger,\n });\n }\n\n if (consentManager.unknownRequestPolicy) {\n await makeGraphQLRequest(client, TOGGLE_UNKNOWN_REQUEST_POLICY, {\n variables: {\n input: {\n id: airgapBundleId,\n unknownRequestPolicy: consentManager.unknownRequestPolicy,\n },\n },\n logger,\n });\n }\n\n if (consentManager.unknownRequestPolicy) {\n await makeGraphQLRequest(client, TOGGLE_UNKNOWN_COOKIE_POLICY, {\n variables: {\n input: {\n id: airgapBundleId,\n unknownCookiePolicy: consentManager.unknownCookiePolicy,\n },\n },\n logger,\n });\n }\n\n if (consentManager.telemetryPartitioning) {\n await makeGraphQLRequest(client, TOGGLE_TELEMETRY_PARTITION_STRATEGY, {\n variables: {\n input: {\n id: airgapBundleId,\n strategy: consentManager.telemetryPartitioning,\n },\n },\n logger,\n });\n }\n\n if (consentManager.consentPrecedence) {\n await makeGraphQLRequest(client, TOGGLE_CONSENT_PRECEDENCE, {\n variables: {\n input: {\n id: airgapBundleId,\n consentPrecedence: consentManager.consentPrecedence,\n },\n },\n logger,\n });\n }\n\n if (consentManager.experiences) {\n await syncConsentManagerExperiences(client, consentManager.experiences, {\n logger,\n });\n }\n\n if (consentManager.theme) {\n await makeGraphQLRequest(client, UPDATE_CONSENT_MANAGER_THEME, {\n variables: {\n input: {\n airgapBundleId,\n ...consentManager.theme,\n },\n },\n logger,\n });\n }\n\n // TODO: https://transcend.height.app/T-23875\n // syncEndpoint: string;\n // TODO: https://transcend.height.app/T-23919\n // syncGroups: string;\n}\n","import { ConsentTrackerStatus } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchConsentManagerId } from './fetchConsentManagerId.js';\nimport { UPDATE_OR_CREATE_COOKIES } from './gqls/cookies.js';\n\nexport interface CookieInput {\n /** Name of cookie */\n name: string;\n /** Whether or not the cookie is a regular expression */\n isRegex?: boolean;\n /** Description of cookie */\n description?: string;\n /** The tracking purposes that are required to be opted in for this cookie */\n trackingPurposes?: string[];\n /** Name of the consent service attached */\n service?: string;\n /** Status of the tracker (approved vs triage) */\n status?: ConsentTrackerStatus;\n /** Email addresses of owners */\n owners?: string[];\n /** Names of teams responsible for managing this cookie */\n teams?: string[];\n /** Attribute key-value pairs */\n attributes?: {\n /** Attribute key */\n key: string;\n /** Attribute values */\n values: string[];\n }[];\n}\n\nconst MAX_PAGE_SIZE = 100;\n\n/**\n * Update or create cookies\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateOrCreateCookies(\n client: GraphQLClient,\n options: {\n /** List of cookie inputs */\n input: CookieInput[];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: cookies, logger = NOOP_LOGGER } = options;\n const airgapBundleId = await fetchConsentManagerId(client, { logger });\n\n await mapSeries(chunk(cookies, MAX_PAGE_SIZE), async (page) => {\n await makeGraphQLRequest(client, UPDATE_OR_CREATE_COOKIES, {\n variables: {\n airgapBundleId,\n cookies: page.map((cookie) => ({\n name: cookie.name,\n trackingPurposes:\n cookie.trackingPurposes && cookie.trackingPurposes.length > 0\n ? cookie.trackingPurposes\n : undefined,\n description: cookie.description,\n service: cookie.service,\n status: cookie.status,\n attributes: cookie.attributes,\n isRegex: cookie.isRegex,\n })),\n },\n logger,\n });\n });\n}\n\n/**\n * Sync the set of cookies into the product\n *\n * @param client - GraphQL client\n * @param cookies - Cookies to sync\n * @param options - Options\n * @returns True upon success, false upon failure\n */\nexport async function syncCookies(\n client: GraphQLClient,\n cookies: CookieInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${cookies.length}\" cookies...`);\n\n const notUnique = cookies.filter(\n (cookie) =>\n cookies.filter((cook) => cookie.name === cook.name && cookie.isRegex === cook.isRegex)\n .length > 1,\n );\n if (notUnique.length > 0) {\n throw new Error(\n `Failed to upload cookies as there were non-unique entries found: ${notUnique\n .map(({ name }) => name)\n .join(',')}`,\n );\n }\n\n try {\n logger.info(`Upserting \"${cookies.length}\" new cookies...`);\n await updateOrCreateCookies(client, { input: cookies, logger });\n logger.info(`Successfully synced ${cookies.length} cookies!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create cookies! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import { ConsentTrackerStatus, DataFlowScope } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllDataFlows } from './fetchAllDataFlows.js';\nimport { fetchConsentManagerId } from './fetchConsentManagerId.js';\nimport { CREATE_DATA_FLOWS, UPDATE_DATA_FLOWS } from './gqls/dataFlows.js';\n\n/** Attribute key-value pair for a data flow */\nexport interface DataFlowAttributeInput {\n /** Attribute key */\n key: string;\n /** Attribute values */\n values: string[];\n}\n\n/**\n * Input to define a data flow for sync\n *\n * @see https://app.transcend.io/consent-manager/data-flows/approved\n */\nexport interface DataFlowInput {\n /** Value of data flow */\n value: string;\n /** Type of data flow */\n type: DataFlowScope;\n /** Description of data flow */\n description?: string;\n /** The tracking purposes that are required to be opted in for this data flow */\n trackingPurposes?: string[];\n /** Name of the consent service attached */\n service?: string;\n /** Status of the tracker (approved vs triage) */\n status?: ConsentTrackerStatus;\n /** Email addresses of owners */\n owners?: string[];\n /** Names of teams responsible for managing this data flow */\n teams?: string[];\n /** Attribute key-value pairs */\n attributes?: DataFlowAttributeInput[];\n}\n\nconst MAX_PAGE_SIZE = 100;\n\n/**\n * Update data flows that already existed\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateDataFlows(\n client: GraphQLClient,\n options: {\n /** [DataFlowInput, Data Flow ID] mappings to update */\n input: [DataFlowInput, string][];\n /** Classify service if missing */\n classifyService?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: dataFlows, classifyService = false, logger = NOOP_LOGGER } = options;\n const airgapBundleId = await fetchConsentManagerId(client, { logger });\n\n // TODO: https://transcend.height.app/T-19841 - add with custom purposes\n // const purposes = await fetchAllPurposes(client);\n // const purposeNameToId = keyBy(purposes, 'name');\n\n await mapSeries(chunk(dataFlows, MAX_PAGE_SIZE), async (page) => {\n await makeGraphQLRequest(client, UPDATE_DATA_FLOWS, {\n variables: {\n airgapBundleId,\n dataFlows: page.map(([flow, id]) => ({\n id,\n value: flow.value,\n type: flow.type,\n trackingType:\n flow.trackingPurposes && flow.trackingPurposes.length > 0\n ? flow.trackingPurposes\n : undefined,\n // TODO: https://transcend.height.app/T-19841 - add with custom purposes\n // purposeIds: flow.trackingPurposes\n // ? flow.trackingPurposes\n // .filter((purpose) => purpose !== 'Unknown')\n // .map((purpose) => purposeNameToId[purpose].id)\n // : undefined,\n description: flow.description,\n service: flow.service,\n status: flow.status,\n attributes: flow.attributes,\n // TODO: https://transcend.height.app/T-23718\n // owners,\n // teams,\n })),\n classifyService,\n },\n logger,\n });\n });\n}\n\n/**\n * Create new data flows\n *\n * @param client - GraphQL client\n * @param dataFlowInputs - List of data flows to create\n * @param options - Options\n */\nexport async function createDataFlows(\n client: GraphQLClient,\n options: {\n /** Data flow inputs to create */\n input: DataFlowInput[];\n /** Classify service if missing */\n classifyService?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: dataFlowInputs, classifyService = false, logger = NOOP_LOGGER } = options;\n const airgapBundleId = await fetchConsentManagerId(client, { logger });\n\n // TODO: https://transcend.height.app/T-19841 - add with custom purposes\n // const purposes = await fetchAllPurposes(client);\n // const purposeNameToId = keyBy(purposes, 'name');\n\n await mapSeries(chunk(dataFlowInputs, MAX_PAGE_SIZE), async (page) => {\n await makeGraphQLRequest(client, CREATE_DATA_FLOWS, {\n variables: {\n airgapBundleId,\n dataFlows: page.map((flow) => ({\n value: flow.value,\n type: flow.type,\n trackingType:\n flow.trackingPurposes && flow.trackingPurposes.length > 0\n ? flow.trackingPurposes\n : undefined,\n // TODO: https://transcend.height.app/T-19841 - add with custom purposes\n // purposeIds: flow.trackingPurposes\n // ? flow.trackingPurposes\n // .filter((purpose) => purpose !== 'Unknown')\n // .map((purpose) => purposeNameToId[purpose].id)\n // : undefined,\n description: flow.description,\n service: flow.service,\n status: flow.status,\n attributes: flow.attributes,\n // TODO: https://transcend.height.app/T-23718\n // owners,\n // teams,\n })),\n classifyService,\n },\n logger,\n });\n });\n}\n\n/**\n * Sync data flow configurations into Transcend\n *\n * @param client - GraphQL client\n * @param dataFlows - The data flows to upload\n * @param options - Options\n * @returns True if the command ran successfully, returns false if an error occurred\n */\nexport async function syncDataFlows(\n client: GraphQLClient,\n dataFlows: DataFlowInput[],\n options: {\n /** When true, auto classify the service based on the data flow value */\n classifyService?: boolean;\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { classifyService = false, logger = NOOP_LOGGER } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${dataFlows.length}\" data flows...`);\n\n const notUnique = dataFlows.filter(\n (dataFlow) =>\n dataFlows.filter((flow) => dataFlow.value === flow.value && dataFlow.type === flow.type)\n .length > 1,\n );\n\n if (notUnique.length > 0) {\n throw new Error(\n `Failed to upload data flows as there were non-unique entries found: ${notUnique\n .map(({ value }) => value)\n .join(',')}`,\n );\n }\n\n logger.info('Fetching data flows...');\n const [existingLiveDataFlows, existingInReviewDataFlows] = await Promise.all([\n fetchAllDataFlows(client, {\n logger,\n filterBy: { status: ConsentTrackerStatus.Live },\n }),\n fetchAllDataFlows(client, {\n logger,\n filterBy: { status: ConsentTrackerStatus.NeedsReview },\n }),\n ]);\n const allDataFlows = [...existingLiveDataFlows, ...existingInReviewDataFlows];\n\n const mapDataFlowsToExisting = dataFlows.map((dataFlow) => [\n dataFlow,\n allDataFlows.find((flow) => dataFlow.value === flow.value && dataFlow.type === flow.type)?.id,\n ]);\n\n const newDataFlows = mapDataFlowsToExisting\n .filter(([, existing]) => !existing)\n .map(([flow]) => flow as DataFlowInput);\n try {\n logger.info(`Creating \"${newDataFlows.length}\" new data flows...`);\n await createDataFlows(client, { input: newDataFlows, classifyService, logger });\n logger.info(`Successfully synced ${newDataFlows.length} data flows!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create data flows! - ${(err as Error).message}`);\n }\n\n const existingDataFlows = mapDataFlowsToExisting.filter(\n (x): x is [DataFlowInput, string] => !!x[1],\n );\n try {\n logger.info(`Updating \"${existingDataFlows.length}\" data flows...`);\n await updateDataFlows(client, { input: existingDataFlows, classifyService, logger });\n logger.info(`Successfully updated \"${existingDataFlows.length}\" data flows!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to update data flows! - ${(err as Error).message}`);\n }\n\n logger.info(`Synced \"${dataFlows.length}\" data flows!`);\n\n return !encounteredError;\n}\n","import type { LocaleValue } from '@transcend-io/internationalization';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk, keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllPolicies } from './fetchAllPolicies.js';\nimport { fetchPrivacyCenterId } from './fetchPrivacyCenterId.js';\nimport { UPDATE_POLICIES } from './gqls/policy.js';\n\nexport interface PolicyInput {\n /** The title of the policy */\n title: string;\n /** Effective date of policy */\n effectiveOn?: string;\n /** Whether or not to disable the effective date */\n disableEffectiveOn?: boolean;\n /** Content of the policy */\n content?: string;\n /** The languages for which the policy is disabled for */\n disabledLocales?: LocaleValue[];\n}\n\nconst MAX_PAGE_SIZE = 100;\n\n/**\n * Update or create policies\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updatePolicies(\n client: GraphQLClient,\n options: {\n /** [PolicyInput, policyId] list */\n input: [PolicyInput, string | undefined][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: policyInputs, logger = NOOP_LOGGER } = options;\n const privacyCenterId = await fetchPrivacyCenterId(client, { logger });\n\n await mapSeries(chunk(policyInputs, MAX_PAGE_SIZE), async (page) => {\n await makeGraphQLRequest(client, UPDATE_POLICIES, {\n variables: {\n privacyCenterId,\n policies: page.map(([policy, policyId]) => ({\n id: policyId,\n title: policy.title,\n disableEffectiveOn: policy.disableEffectiveOn,\n disabledLocales: policy.disabledLocales,\n ...(policy.effectiveOn || policy.content\n ? {\n version: {\n ...(policy.effectiveOn ? { effectiveOn: policy.effectiveOn } : {}),\n ...(policy.content\n ? {\n content: {\n defaultMessage: policy.content,\n },\n }\n : {}),\n },\n }\n : {}),\n })),\n },\n logger,\n });\n });\n}\n\n/**\n * Sync the set of policies from the YML interface into the product\n *\n * @param client - GraphQL client\n * @param policies - policies to sync\n * @param options - Options\n * @returns True upon success, false upon failure\n */\nexport async function syncPolicies(\n client: GraphQLClient,\n policies: PolicyInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${policies.length}\" policies...`);\n\n const notUnique = policies.filter(\n (policy) => policies.filter((pol) => policy.title === pol.title).length > 1,\n );\n if (notUnique.length > 0) {\n throw new Error(\n `Failed to upload policies as there were non-unique entries found: ${notUnique\n .map(({ title }) => title)\n .join(',')}`,\n );\n }\n\n const existingPolicies = await fetchAllPolicies(client, { logger });\n const policiesById = keyBy(existingPolicies, ({ title }) => title.defaultMessage);\n\n try {\n logger.info(`Upserting \"${policies.length}\" new policies...`);\n await updatePolicies(client, {\n input: policies.map((policy) => [policy, policiesById[policy.title]?.id]),\n logger,\n });\n logger.info(`Successfully synced ${policies.length} policies!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create policies! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import type { LocaleValue } from '@transcend-io/internationalization';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchPrivacyCenterId } from './fetchPrivacyCenterId.js';\nimport { UPDATE_PRIVACY_CENTER } from './gqls/privacyCenter.js';\n\nexport interface PrivacyCenterInput {\n /** Whether or not the entire privacy center is enabled or disabled */\n isDisabled?: boolean;\n /** Whether or not to show the privacy requests button */\n showPrivacyRequestButton?: boolean;\n /** Whether or not to show the data practices page */\n showDataPractices?: boolean;\n /** Whether or not to show the policies page */\n showPolicies?: boolean;\n /** Whether or not to show the tracking technologies page */\n showTrackingTechnologies?: boolean;\n /** Whether or not to show the cookies on the tracking technologies page */\n showCookies?: boolean;\n /** Whether or not to show the data flows on the tracking technologies page */\n showDataFlows?: boolean;\n /** Whether or not to show the consent manager opt out options on the tracking technologies page */\n showConsentManager?: boolean;\n /** Whether or not to show the manage your privacy page */\n showManageYourPrivacy?: boolean;\n /** Whether or not to show the marketing preferences page */\n showMarketingPreferences?: boolean;\n /** What languages are supported for the privacy center */\n locales?: LocaleValue[];\n /** The default locale for the privacy center */\n defaultLocale?: LocaleValue;\n /** Whether or not to prefer the browser default locale */\n preferBrowserDefaultLocale?: boolean;\n /** The support email address */\n supportEmail?: string;\n /** The reply-to email address */\n replyToEmail?: string;\n /** Whether or not to send emails from a no reply email */\n useNoReplyEmailAddress?: boolean;\n /** Whether or not to use a custom email domain */\n useCustomEmailDomain?: boolean;\n /** Whether or not to transcend access requests from JSON to CSV */\n transformAccessReportJsonToCsv?: boolean;\n /** The theme object of colors to display on the privacy center */\n theme?: {\n /** The theme colors */\n colors?: Record<string, string | undefined>;\n /** Styles to apply to components */\n componentStyles?: Record<string, unknown>;\n /** Override styles */\n textStyles?: Record<string, unknown>;\n };\n}\n\n/**\n * Sync the privacy center\n *\n * @param client - GraphQL client\n * @param privacyCenter - The privacy center input\n * @param options - Options\n * @returns Whether the privacy center was synced successfully\n */\nexport async function syncPrivacyCenter(\n client: GraphQLClient,\n privacyCenter: PrivacyCenterInput,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n let encounteredError = false;\n logger.info('Syncing privacy center...');\n\n const privacyCenterId = await fetchPrivacyCenterId(client, { logger });\n\n try {\n await makeGraphQLRequest(client, UPDATE_PRIVACY_CENTER, {\n variables: {\n input: {\n privacyCenterId,\n transformAccessReportJsonToCsv: privacyCenter.transformAccessReportJsonToCsv,\n useCustomEmailDomain: privacyCenter.useCustomEmailDomain,\n useNoReplyEmailAddress: privacyCenter.useNoReplyEmailAddress,\n replyToEmail: privacyCenter.replyToEmail,\n supportEmail: privacyCenter.supportEmail,\n preferBrowserDefaultLocale: privacyCenter.preferBrowserDefaultLocale,\n defaultLocale: privacyCenter.defaultLocale,\n locales: privacyCenter.locales,\n showMarketingPreferences: privacyCenter.showMarketingPreferences,\n showManageYourPrivacy: privacyCenter.showManageYourPrivacy,\n showPolicies: privacyCenter.showPolicies,\n showConsentManager: privacyCenter.showConsentManager,\n showDataFlows: privacyCenter.showDataFlows,\n showCookies: privacyCenter.showCookies,\n showTrackingTechnologies: privacyCenter.showTrackingTechnologies,\n showPrivacyRequestButton: privacyCenter.showPrivacyRequestButton,\n isDisabled: privacyCenter.isDisabled,\n ...(privacyCenter.theme\n ? {\n colorPalette: privacyCenter.theme.colors,\n componentStyles: privacyCenter.theme.componentStyles,\n textStyles: privacyCenter.theme.textStyles,\n }\n : {}),\n },\n },\n logger,\n });\n logger.info('Successfully synced privacy center!');\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create privacy center! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import { ProcessingPurpose } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport {\n fetchAllProcessingPurposes,\n type ProcessingPurposeSubCategory,\n} from './fetchAllProcessingPurposes.js';\nimport {\n UPDATE_PROCESSING_PURPOSE_SUB_CATEGORIES,\n CREATE_PROCESSING_PURPOSE_SUB_CATEGORY,\n} from './gqls/processingPurpose.js';\n\nexport interface ProcessingPurposeInput {\n /** Name of processing purpose */\n name: string;\n /** Type of processing purpose */\n purpose: ProcessingPurpose;\n /** Description of processing purpose */\n description?: string;\n /** Owner email addresses */\n owners?: string[];\n /** Team names */\n teams?: string[];\n /** Attribute key-value pairs */\n attributes?: {\n /** Attribute key */\n key: string;\n /** Attribute values */\n values: string[];\n }[];\n}\n\n/**\n * Input to create a new processing purpose\n *\n * @param client - GraphQL client\n * @param processingPurpose - Input\n * @param options - Options\n * @returns Created processing purpose\n */\nexport async function createProcessingPurpose(\n client: GraphQLClient,\n options: {\n /** Processing purpose to create */\n input: ProcessingPurposeInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<ProcessingPurposeSubCategory, 'id' | 'name' | 'purpose'>> {\n const { input: processingPurpose, logger } = options;\n const gqlInput = {\n name: processingPurpose.name,\n purpose: processingPurpose.purpose,\n description: processingPurpose.description,\n // TODO: https://transcend.height.app/T-31994 - add attributes, teams, owners\n };\n\n const { createProcessingPurposeSubCategory } = await makeGraphQLRequest<{\n /** Create processing purpose mutation */\n createProcessingPurposeSubCategory: {\n /** Created processing purpose */\n processingPurposeSubCategory: ProcessingPurposeSubCategory;\n };\n }>(client, CREATE_PROCESSING_PURPOSE_SUB_CATEGORY, {\n variables: { input: gqlInput },\n logger,\n });\n return createProcessingPurposeSubCategory.processingPurposeSubCategory;\n}\n\n/**\n * Input to update processing purposes\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateProcessingPurposes(\n client: GraphQLClient,\n options: {\n /** [ProcessingPurposeInput, processingPurposeId] list */\n input: [ProcessingPurposeInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: processingPurposes, logger } = options;\n await makeGraphQLRequest(client, UPDATE_PROCESSING_PURPOSE_SUB_CATEGORIES, {\n variables: {\n input: {\n processingPurposeSubCategories: processingPurposes.map(([processingPurpose, id]) => ({\n id,\n description: processingPurpose.description,\n // TODO: https://transcend.height.app/T-31994 - add teams, owners\n attributes: processingPurpose.attributes,\n })),\n },\n },\n logger,\n });\n}\n\n/**\n * Sync the data inventory processing purposes\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncProcessingPurposes(\n client: GraphQLClient,\n inputs: ProcessingPurposeInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n\n logger.info(`Syncing \"${inputs.length}\" processing purposes...`);\n\n let encounteredError = false;\n\n const existingProcessingPurposes = await fetchAllProcessingPurposes(client, { logger });\n\n const processingPurposeByName: {\n [k in string]: Pick<ProcessingPurposeSubCategory, 'id' | 'name'>;\n } = keyBy(existingProcessingPurposes, ({ name, purpose }) => `${name}:${purpose}`);\n\n const newProcessingPurposes = inputs.filter(\n (input) => !processingPurposeByName[`${input.name}:${input.purpose}`],\n );\n\n await mapSeries(newProcessingPurposes, async (processingPurpose) => {\n try {\n const newProcessingPurpose = await createProcessingPurpose(client, {\n input: processingPurpose,\n logger,\n });\n processingPurposeByName[`${newProcessingPurpose.name}:${newProcessingPurpose.purpose}`] =\n newProcessingPurpose;\n logger.info(`Successfully synced processing purpose \"${processingPurpose.name}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to sync processing purpose \"${processingPurpose.name}\"! - ${(err as Error).message}`,\n );\n }\n });\n\n try {\n logger.info(`Updating \"${inputs.length}\" processing purposes!`);\n await updateProcessingPurposes(client, {\n input: inputs.map((input) => [\n input,\n processingPurposeByName[`${input.name}:${input.purpose}`]!.id,\n ]),\n logger,\n });\n logger.info(`Successfully synced \"${inputs.length}\" processing purposes!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to sync \"${inputs.length}\" processing purposes ! - ${(err as Error).message}`,\n );\n }\n\n return !encounteredError;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const REQUEST_ENRICHERS = gql`\n query TranscendCliRequestEnrichers($first: Int!, $offset: Int!, $requestId: ID!) {\n requestEnrichers(\n input: { requestId: $requestId }\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [\n { field: createdAt, direction: ASC }\n { field: title, direction: ASC, model: enricher }\n ]\n ) {\n nodes {\n id\n status\n enricher {\n id\n type\n title\n }\n }\n totalCount\n }\n }\n`;\n\nexport const RETRY_REQUEST_ENRICHER = gql`\n mutation TranscendCliRetryRequestEnricher($requestEnricherId: ID!) {\n retryRequestEnricher(id: $requestEnricherId) {\n requestEnricher {\n id\n }\n }\n }\n`;\n\nexport const SKIP_REQUEST_ENRICHER = gql`\n mutation TranscendCliSkipRequestEnricher($requestEnricherId: ID!) {\n skipRequestEnricher(id: $requestEnricherId) {\n requestEnricher {\n id\n }\n }\n }\n`;\n","import { RequestEnricherStatus } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { REQUEST_ENRICHERS } from './gqls/requestEnricher.js';\n\nexport interface RequestEnricher {\n /** ID of request enricher */\n id: string;\n /** Name of identifier */\n enricher: {\n /** ID of enricher */\n id: string;\n /** Title of enricher */\n title: string;\n /** Typeof of enricher */\n type: string;\n };\n /** The status of the enricher */\n status: RequestEnricherStatus;\n}\n\nconst PAGE_SIZE = 50;\n\n/**\n * Fetch all request enrichers for a particular request\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns List of request enrichers\n */\nexport async function fetchAllRequestEnrichers(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy: {\n /** ID of request to filter on */\n requestId: string;\n };\n },\n): Promise<RequestEnricher[]> {\n const {\n logger = NOOP_LOGGER,\n filterBy: { requestId },\n } = options;\n const requestEnrichers: RequestEnricher[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n requestEnrichers: { nodes },\n } = await makeGraphQLRequest<{\n /** Request Enrichers */\n requestEnrichers: {\n /** List */\n nodes: RequestEnricher[];\n };\n }>(client, REQUEST_ENRICHERS, {\n variables: { first: PAGE_SIZE, offset, requestId },\n logger,\n });\n requestEnrichers.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return requestEnrichers;\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const SOMBRA_VERSION: DocumentNode = parse(gql`\n query TranscendSombraVersion {\n organization {\n sombra {\n version\n }\n }\n }\n`);\n","import { IdentifierType } from '@transcend-io/privacy-types';\nimport { decodeCodec, valuesOf } from '@transcend-io/type-utils';\nimport type { Logger } from '@transcend-io/utils';\nimport type { Got } from 'got';\nimport { GraphQLClient } from 'graphql-request';\nimport * as t from 'io-ts';\nimport semver from 'semver';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { SOMBRA_VERSION } from './gqls/sombraVersion.js';\n\nconst MIN_SOMBRA_VERSION_TO_DECRYPT = '7.180.0';\n\nconst RequestIdentifier = t.type({\n /** ID of request */\n id: t.string,\n /** Name of identifier */\n name: t.string,\n /** The underlying identifier value */\n value: t.string,\n /** Type of identifier */\n type: valuesOf(IdentifierType),\n});\n\n/** Type override */\nexport type RequestIdentifier = t.TypeOf<typeof RequestIdentifier>;\n\nconst PAGE_SIZE = 50;\n\nexport const RequestIdentifiersResponse = t.type({\n identifiers: t.array(RequestIdentifier),\n});\n\n/**\n * Validate that the Sombra version meets the minimum requirement for\n * decrypting request identifiers. Call once before bulk-fetching identifiers\n * to avoid repeating this check on every request.\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function validateSombraVersion(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n const { logger = NOOP_LOGGER } = options;\n const {\n organization: {\n sombra: { version },\n },\n } = await makeGraphQLRequest<{\n /** The organization */\n organization: {\n /** Sombra */\n sombra: {\n /** Version string */\n version: string;\n };\n };\n }>(client, SOMBRA_VERSION, { logger });\n\n if (version && semver.lt(version, MIN_SOMBRA_VERSION_TO_DECRYPT)) {\n throw new Error(\n `Please upgrade Sombra to ${MIN_SOMBRA_VERSION_TO_DECRYPT} or greater to use this command.`,\n );\n }\n}\n\n/**\n * Fetch all request identifiers for a particular request\n *\n * @param client - GraphQL client\n * @param sombra - Sombra client\n * @param options - Options\n * @returns List of request identifiers\n */\nexport async function fetchAllRequestIdentifiers(\n client: GraphQLClient,\n sombra: Got,\n options: {\n /** Filter options */\n filterBy: {\n /** ID of request to filter on */\n requestId: string;\n };\n /** Skip the Sombra version check (caller already validated) */\n skipSombraCheck?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<RequestIdentifier[]> {\n const {\n filterBy: { requestId },\n skipSombraCheck = false,\n logger = NOOP_LOGGER,\n } = options;\n const requestIdentifiers: RequestIdentifier[] = [];\n let offset = 0;\n let shouldContinue = false;\n\n if (!skipSombraCheck) {\n await validateSombraVersion(client, { logger });\n }\n\n do {\n let response: unknown;\n try {\n response = await sombra!\n .post<{\n /** Decrypted identifiers */\n identifiers: RequestIdentifier[];\n }>('v1/request-identifiers', {\n json: {\n first: PAGE_SIZE,\n offset,\n requestId,\n },\n })\n .json();\n } catch (err) {\n throw new Error(`Failed to fetch request identifiers: ${(err as Error).message}`);\n }\n\n const { identifiers: nodes } = decodeCodec(RequestIdentifiersResponse, response);\n\n requestIdentifiers.push(...nodes);\n\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return requestIdentifiers;\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const REMOVE_REQUEST_IDENTIFIERS: DocumentNode = parse(gql`\n mutation TranscendCliRemoveRequestIdentifiers($input: RemoveRequestIdentifiersInput!) {\n removeRequestIdentifiers(input: $input) {\n count\n }\n }\n`);\n\nexport const REQUEST_IDENTIFIERS: DocumentNode = parse(gql`\n query TranscendCliRequestIdentifiers(\n $first: Int!\n $offset: Int!\n $requestIds: [ID!]\n $updatedAtBefore: Date\n $updatedAtAfter: Date\n ) {\n requestIdentifiers(\n input: {\n requestIds: $requestIds\n updatedAtBefore: $updatedAtBefore\n updatedAtAfter: $updatedAtAfter\n }\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n isVerifiedAtLeastOnce\n }\n totalCount\n }\n }\n`);\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { REQUEST_IDENTIFIERS } from './gqls/requestIdentifier.js';\n\nexport interface RequestIdentifierMetadata {\n /** ID of request identifier */\n id: string;\n /** Name of identifier */\n name: string;\n /** Status of identifier */\n isVerifiedAtLeastOnce: boolean;\n}\n\nconst PAGE_SIZE = 50;\n\n/**\n * Fetch all request identifier metadata for a particular request\n *\n * @param client - GraphQL client\n * @param options - Filter options\n * @returns List of request identifiers\n */\nexport async function fetchAllRequestIdentifierMetadata(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** ID of request to filter on */\n requestId?: string;\n /** IDs of requests to filter on */\n requestIds?: string[];\n /** Filter for request identifiers updated before this date */\n updatedAtBefore?: Date;\n /** Filter for request identifiers updated after this date */\n updatedAtAfter?: Date;\n };\n } = {},\n): Promise<RequestIdentifierMetadata[]> {\n const { logger = NOOP_LOGGER, filterBy } = options;\n const { requestId, requestIds, updatedAtBefore, updatedAtAfter } = filterBy ?? {};\n const resolvedRequestIds = requestIds ?? (requestId ? [requestId] : undefined);\n const requestIdentifiers: RequestIdentifierMetadata[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n requestIdentifiers: { nodes },\n } = await makeGraphQLRequest<{\n /** Request Identifiers */\n requestIdentifiers: {\n /** List */\n nodes: RequestIdentifierMetadata[];\n };\n }>(client, REQUEST_IDENTIFIERS, {\n variables: {\n first: PAGE_SIZE,\n offset,\n requestIds: resolvedRequestIds,\n updatedAtBefore: updatedAtBefore ? updatedAtBefore.toISOString() : undefined,\n updatedAtAfter: updatedAtAfter ? updatedAtAfter.toISOString() : undefined,\n },\n logger,\n });\n requestIdentifiers.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return requestIdentifiers;\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const DATA_SUBJECTS: DocumentNode = parse(gql`\n query TranscendCliDataSubjects {\n internalSubjects {\n id\n title {\n defaultMessage\n }\n active\n type\n adminDashboardDefaultSilentMode\n actions {\n type\n }\n }\n }\n`);\n\nexport const CREATE_DATA_SUBJECT: DocumentNode = parse(gql`\n mutation TranscendCliCreateDataSubject($type: String!) {\n createSubject(input: { type: $type, title: $type, subjectClass: OTHER }) {\n subject {\n id\n type\n }\n }\n }\n`);\n\nexport const UPDATE_DATA_SUBJECT: DocumentNode = parse(gql`\n mutation TranscendCliUpdateDataSubject($input: UpdateSubjectInput!) {\n updateSubject(input: $input) {\n clientMutationId\n }\n }\n`);\n\nexport const TOGGLE_DATA_SUBJECT: DocumentNode = parse(gql`\n mutation TranscendCliToggleDataSubject($input: ToggleSubjectInput!) {\n toggleSubject(input: $input) {\n clientMutationId\n }\n }\n`);\n","import { RequestActionObjectResolver } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { CREATE_DATA_SUBJECT, DATA_SUBJECTS } from './gqls/dataSubject.js';\n\nexport interface DataSubject {\n /** ID of data subject */\n id: string;\n /** Type of data subject */\n type: string;\n /** Whether active */\n active: boolean;\n /** Title of data subject */\n title: {\n /** Default message */\n defaultMessage: string;\n };\n /** Whether silent mode is enabled by default */\n adminDashboardDefaultSilentMode: boolean;\n /** Enabled actions */\n actions: {\n /** Type of action */\n type: RequestActionObjectResolver;\n }[];\n}\n\n/**\n * Fetch all data subjects in an organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns List of data subject configurations\n */\nexport async function fetchAllDataSubjects(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<DataSubject[]> {\n const { logger = NOOP_LOGGER } = options;\n const { internalSubjects } = await makeGraphQLRequest<{\n /** Query response */\n internalSubjects: DataSubject[];\n }>(client, DATA_SUBJECTS, { logger });\n return internalSubjects;\n}\n\n/**\n * Create a single data subject\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Created data subject\n */\nexport async function createDataSubject(\n client: GraphQLClient,\n options: {\n /** The type string for the new subject */\n input: string;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<DataSubject> {\n const { input: dataSubjectType, logger = NOOP_LOGGER } = options;\n const { createSubject } = await makeGraphQLRequest<{\n /** Create Subject Response */\n createSubject: {\n /** Created Data Subject */\n subject: DataSubject;\n };\n }>(client, CREATE_DATA_SUBJECT, {\n variables: { type: dataSubjectType, skipPublish: true },\n logger,\n });\n return createSubject.subject;\n}\n\n/**\n * Convert a list of data subject types into the block list of IDs to assign to the data silo\n *\n * @param dataSubjectTypes - The list of data subject types that the data silo should be for\n * @param allDataSubjects - All data subjects in the organization\n * @returns The block list of data subject ids to not process against this data silo\n */\nexport function convertToDataSubjectBlockList(\n dataSubjectTypes: string[],\n allDataSubjects: { [type in string]: DataSubject },\n): string[] {\n dataSubjectTypes.forEach((type) => {\n if (!allDataSubjects[type]) {\n throw new Error(`Expected to find data subject definition: ${type}`);\n }\n });\n\n return Object.values(allDataSubjects)\n .filter((silo) => !dataSubjectTypes.includes(silo.type))\n .map(({ id }) => id);\n}\n\n/**\n * Convert a list of data subject types into the allow list of types\n *\n * @param dataSubjectTypes - The list of data subject types that the data silo should be for\n * @param allDataSubjects - All data subjects in the organization\n * @returns The allow list of data subjects for that silo\n */\nexport function convertToDataSubjectAllowlist(\n dataSubjectTypes: string[],\n allDataSubjects: { [type in string]: DataSubject },\n): string[] {\n dataSubjectTypes.forEach((type) => {\n if (!allDataSubjects[type]) {\n throw new Error(`Expected to find data subject definition: ${type}`);\n }\n });\n\n return Object.values(allDataSubjects)\n .filter((silo) => !dataSubjectTypes.includes(silo.type))\n .map(({ type }) => type);\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const NEW_IDENTIFIER_TYPES: DocumentNode = parse(gql`\n query TranscendCliNewIdentifierTypes {\n newIdentifierTypes {\n name\n }\n }\n`);\n\nexport const CREATE_IDENTIFIER: DocumentNode = parse(gql`\n mutation TranscendCliCreateIdentifier($input: IdentifierInput!) {\n createIdentifier(input: $input) {\n identifier {\n id\n name\n }\n }\n }\n`);\n\nexport const UPDATE_IDENTIFIER: DocumentNode = parse(gql`\n mutation TranscendCliUpdateIdentifier($input: UpdateIdentifierInput!) {\n updateIdentifier(input: $input) {\n clientMutationId\n }\n }\n`);\n","import { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy, uniq, flatten, difference } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllIdentifiers, type Identifier } from '../data-inventory/fetchAllIdentifiers.js';\nimport { CREATE_IDENTIFIER, NEW_IDENTIFIER_TYPES } from './gqls/dsrIdentifier.js';\n\nexport interface IdentifiersAndCreateMissingInput {\n /** Enricher configurations */\n enrichers?: {\n /** Input identifier name */\n 'input-identifier'?: string;\n /** Output identifier names */\n 'output-identifiers': string[];\n }[];\n /** Data silo configurations */\n 'data-silos'?: {\n /** Identity keys */\n 'identity-keys'?: string[];\n }[];\n /** Identifier configurations */\n identifiers?: {\n /** Identifier name */\n name: string;\n }[];\n}\n\n/**\n * Fetch all identifiers and if any are found in the config that are\n * missing, create those identifiers.\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns A map from identifier name to Identifier\n */\nexport async function fetchIdentifiersAndCreateMissing(\n client: GraphQLClient,\n options: {\n /** Transcend input configuration */\n input: IdentifiersAndCreateMissingInput;\n /** When true, skip publishing to privacy center */\n skipPublish?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<{ [k in string]: Identifier }> {\n const { input, skipPublish = false, logger = NOOP_LOGGER } = options;\n const { enrichers = [], 'data-silos': dataSilos = [], identifiers = [] } = input;\n const allIdentifiers = await fetchAllIdentifiers(client, { logger });\n const identifiersByName = keyBy(allIdentifiers, 'name');\n\n const expectedIdentifiers = uniq([\n ...flatten(\n enrichers.map((enricher) => [\n enricher['input-identifier'],\n ...enricher['output-identifiers'],\n ]),\n ),\n ...flatten(dataSilos.map((dataSilo) => dataSilo['identity-keys'])),\n ...identifiers.map(({ name }) => name),\n ]).filter((x) => !!x);\n const missingIdentifiers = difference(\n expectedIdentifiers,\n allIdentifiers.map(({ name }) => name),\n );\n\n if (missingIdentifiers.length > 0) {\n logger.info(`Creating ${missingIdentifiers.length} new identifiers...`);\n const { newIdentifierTypes } = await makeGraphQLRequest<{\n /** Query response */\n newIdentifierTypes: {\n /** Name of identifier type remaining */\n name: string;\n }[];\n }>(client, NEW_IDENTIFIER_TYPES, { logger });\n const nativeTypesRemaining = newIdentifierTypes.map(({ name }) => name);\n await mapSeries(missingIdentifiers, async (identifier) => {\n logger.info(`Creating identifier ${identifier}...`);\n try {\n const { createIdentifier } = await makeGraphQLRequest<{\n /** createIdentifier Response */\n createIdentifier: {\n /** Created identifier */\n identifier: Identifier;\n };\n }>(client, CREATE_IDENTIFIER, {\n variables: {\n input: {\n name: identifier,\n type: nativeTypesRemaining.includes(identifier!) ? identifier : 'custom',\n skipPublish,\n },\n },\n logger,\n });\n logger.info(`Created identifier ${identifier}!`);\n\n identifiersByName[identifier!] = createIdentifier.identifier;\n } catch (err) {\n logger.error(`Failed to create identifier \"${identifier}\" - ${(err as Error).message}`);\n }\n });\n }\n return identifiersByName;\n}\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { RETRY_REQUEST_ENRICHER } from './gqls/requestEnricher.js';\n\n/**\n * Retry a request enricher\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function retryRequestEnricher(\n client: GraphQLClient,\n options: {\n /** The ID of the request enricher to restart */\n id: string;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { id, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, RETRY_REQUEST_ENRICHER, {\n variables: { requestEnricherId: id },\n logger,\n });\n}\n","import { RequestAction } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { TOGGLE_DATA_SUBJECT, UPDATE_DATA_SUBJECT } from './gqls/dataSubject.js';\n\nexport interface DataSubjectInput {\n /** The type of the data subject */\n type: string;\n /** Whether the data subject is active on the Privacy Center & DSR API */\n active?: boolean;\n /** The title of the data subject */\n title?: string;\n /** Whether or not to default new requests made in the admin dashboard to silent mode */\n adminDashboardDefaultSilentMode?: boolean;\n /** Enabled request actions for the data subject */\n actions?: RequestAction[];\n}\n\n/**\n * Sync the data subjects\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function syncDataSubject(\n client: GraphQLClient,\n options: {\n /** DataSubject update input */\n input: DataSubjectInput;\n /** Existing data subject Id */\n dataSubjectId: string;\n /** When true, skip publishing to privacy center */\n skipPublish?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: dataSubject, dataSubjectId, skipPublish = false, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_DATA_SUBJECT, {\n variables: {\n input: {\n id: dataSubjectId,\n title: dataSubject.title,\n adminDashboardDefaultSilentMode: dataSubject.adminDashboardDefaultSilentMode,\n actions: dataSubject.actions,\n skipPublish: skipPublish && typeof dataSubject.active === 'undefined',\n },\n },\n logger,\n });\n\n if (typeof dataSubject.active === 'boolean') {\n await makeGraphQLRequest(client, TOGGLE_DATA_SUBJECT, {\n variables: {\n input: {\n id: dataSubjectId,\n active: dataSubject.active,\n skipPublish,\n },\n },\n logger,\n });\n }\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const ENRICHERS = gql`\n query TranscendCliEnrichers($title: String, $first: Int!, $offset: Int!) {\n enrichers(\n filterBy: { text: $title }\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n ) {\n nodes {\n id\n title\n url\n type\n expirationDuration\n lookerQueryTitle\n testRegex\n transitionRequestStatus\n phoneNumbers\n regionList\n inputIdentifier {\n name\n }\n identifiers {\n name\n }\n dataSubjects {\n type\n }\n actions\n }\n }\n }\n`;\n\nexport interface Initializer {\n /** ID of enricher */\n id: string;\n /** Identifiers */\n identifiers: {\n /** Name of identifier */\n name: string;\n }[];\n}\n\nexport const INITIALIZER = gql`\n query TranscendCliInitializer {\n initializer {\n id\n identifiers {\n name\n }\n }\n }\n`;\n\nexport const CREATE_ENRICHER = gql`\n mutation TranscendCliCreateEnricher($input: EnricherInput!) {\n createEnricher(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const UPDATE_ENRICHER = gql`\n mutation TranscendCliUpdateEnricher($input: UpdateEnricherInput!) {\n updateEnricher(input: $input) {\n clientMutationId\n }\n }\n`;\n","import {\n EnricherType,\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n PreflightRequestStatus,\n RequestAction,\n} from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport type { Identifier } from '../data-inventory/fetchAllIdentifiers.js';\nimport { ENRICHERS, CREATE_ENRICHER, UPDATE_ENRICHER } from './gqls/enricher.js';\n\nexport interface EnricherInput {\n /** The display title of the enricher */\n title: string;\n /** The names of the identifiers that can be resolved by this enricher */\n 'output-identifiers': string[];\n /** Internal description for why the enricher is needed */\n description?: string;\n /** The URL of the enricher */\n url?: string;\n /** The type of enricher */\n type?: EnricherType;\n /** The name of the identifier that will be the input to this enricher */\n 'input-identifier'?: string;\n /** A regular expression that can be used to match on for cancellation */\n testRegex?: string;\n /** For looker integration - the title of the looker query to run */\n lookerQueryTitle?: string;\n /** The duration (in ms) that the enricher should take to execute */\n expirationDuration?: number;\n /** The status that the enricher should transfer to when condition is met */\n transitionRequestStatus?: PreflightRequestStatus;\n /** For twilio integration - the phone numbers that can be used to send text codes */\n phoneNumbers?: string[];\n /** The list of regions that should trigger the preflight check */\n regionList?: (IsoCountryCode | IsoCountrySubdivisionCode)[];\n /** Specify which data subjects the enricher should run for */\n 'data-subjects'?: string[];\n /** Headers to include in the webhook */\n headers?: {\n /** Header name */\n name: string;\n /** Header value */\n value: string;\n /** Whether the value is a secret */\n isSecret?: boolean;\n }[];\n /** The privacy actions that the enricher should run against */\n 'privacy-actions'?: RequestAction[];\n}\n\nexport interface Enricher {\n /** ID of enricher */\n id: string;\n /** Title of enricher */\n title: string;\n /** URL of enricher */\n url: string;\n /** Server silo */\n type: EnricherType;\n /** Input identifier */\n inputIdentifier: {\n /** Identifier name */\n name: string;\n };\n /** The selected actions */\n actions: RequestAction[];\n /** Output identifiers */\n identifiers: {\n /** Identifier name */\n name: string;\n }[];\n /** Data subjects that the preflight check is configured for */\n dataSubjects: {\n /** Data subject type */\n type: string;\n }[];\n /** The duration (in ms) that the enricher should take to execute. - BigInt */\n expirationDuration: string;\n /** Looker query title */\n lookerQueryTitle?: string;\n /** A regular expression that can be used to match on for cancelation */\n testRegex?: string;\n /** The status that the enricher should transfer to when condition is met. */\n transitionRequestStatus?: PreflightRequestStatus;\n /** The twilio phone number to send from */\n phoneNumbers: string[];\n /** The list of regions that should trigger the enrichment condition */\n regionList: (IsoCountryCode | IsoCountrySubdivisionCode)[];\n}\n\nexport interface DataSubjectRef {\n /** ID of data subject */\n id: string;\n /** Type of data subject */\n type: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all enrichers in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All enrichers in the organization\n */\nexport async function fetchAllEnrichers(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** Filter by title */\n title?: string;\n };\n } = {},\n): Promise<Enricher[]> {\n const { logger = NOOP_LOGGER, filterBy } = options;\n const { title } = filterBy ?? {};\n const enrichers: Enricher[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n enrichers: { nodes },\n } = await makeGraphQLRequest<{\n /** Query response */\n enrichers: {\n /** List of matches */\n nodes: Enricher[];\n };\n }>(client, ENRICHERS, {\n variables: { first: PAGE_SIZE, offset, title },\n logger,\n });\n enrichers.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return enrichers.sort((a, b) => a.title.localeCompare(b.title));\n}\n\n/**\n * Sync an enricher configuration\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function syncEnricher(\n client: GraphQLClient,\n options: {\n /** The enricher input */\n input: EnricherInput;\n /** Index of identifiers in the organization */\n identifierByName: { [name in string]: Identifier };\n /** Lookup data subject by name */\n dataSubjectsByName: { [name in string]: DataSubjectRef };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: enricher, identifierByName, dataSubjectsByName, logger = NOOP_LOGGER } = options;\n const matches = await fetchAllEnrichers(client, {\n filterBy: { title: enricher.title },\n logger,\n });\n const existingEnricher = matches.find(({ title }) => title === enricher.title);\n\n const dataSubjectIds = enricher['data-subjects']?.map((subject) => {\n const existing = dataSubjectsByName[subject];\n if (!existing) {\n throw new Error(`Failed to find a data subject with name: ${subject}`);\n }\n return existing.id;\n });\n\n const inputIdentifier = enricher['input-identifier'];\n const actionUpdates = enricher['privacy-actions'] || Object.values(RequestAction);\n if (existingEnricher) {\n await makeGraphQLRequest(client, UPDATE_ENRICHER, {\n variables: {\n input: {\n id: existingEnricher.id,\n title: enricher.title,\n url: enricher.url,\n headers: enricher.headers,\n testRegex: enricher.testRegex,\n lookerQueryTitle: enricher.lookerQueryTitle,\n expirationDuration:\n typeof enricher.expirationDuration === 'number'\n ? enricher.expirationDuration.toString()\n : undefined,\n transitionRequestStatus: enricher.transitionRequestStatus,\n phoneNumbers: enricher.phoneNumbers,\n regionList: enricher.regionList,\n dataSubjectIds,\n description: enricher.description || '',\n inputIdentifier: inputIdentifier ? identifierByName[inputIdentifier]!.id : undefined,\n identifiers: enricher['output-identifiers']!.map((id) => identifierByName[id]!.id),\n ...(existingEnricher.type === EnricherType.Sombra ? {} : { actions: actionUpdates }),\n },\n },\n logger,\n });\n } else if (inputIdentifier) {\n await makeGraphQLRequest(client, CREATE_ENRICHER, {\n variables: {\n input: {\n title: enricher.title,\n url: enricher.url,\n type: enricher.type || EnricherType.Server,\n headers: enricher.headers,\n testRegex: enricher.testRegex,\n lookerQueryTitle: enricher.lookerQueryTitle,\n expirationDuration:\n typeof enricher.expirationDuration === 'number'\n ? enricher.expirationDuration.toString()\n : undefined,\n transitionRequestStatus: enricher.transitionRequestStatus,\n phoneNumbers: enricher.phoneNumbers,\n dataSubjectIds,\n regionList: enricher.regionList,\n description: enricher.description || '',\n inputIdentifier: identifierByName[inputIdentifier]!.id,\n identifiers: enricher['output-identifiers'].map((id) => identifierByName[id]!.id),\n actions: actionUpdates,\n },\n },\n logger,\n });\n }\n}\n","import { RequestAction } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport type { DataSubject } from './fetchDataSubjects.js';\nimport { UPDATE_IDENTIFIER } from './gqls/dsrIdentifier.js';\n\nexport interface IdentifierInput {\n /** The name of the identifier */\n name: string;\n /** The type of the identifier */\n type: string;\n /** Regular expression to verify the identifier */\n regex?: string;\n /** The fixed set of options that an identifier can take on */\n selectOptions?: string[];\n /** Whether or not the identifier is shown in the privacy center form */\n privacyCenterVisibility?: RequestAction[];\n /** The set of data subjects that this identifier is enabled for */\n dataSubjects?: string[];\n /** When true, the identifier is a required field on the privacy center form */\n isRequiredInForm?: boolean;\n /** Placeholder message for identifier */\n placeholder?: string;\n /** Display title for identifier */\n displayTitle?: string;\n /** Display description for identifier */\n displayDescription?: string;\n /** The display order for the identifier */\n displayOrder?: number;\n /** Whether or not the identifier is unique on the preference store */\n isUniqueOnPreferenceStore?: boolean;\n}\n\n/**\n * Sync a single identifier\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function syncIdentifier(\n client: GraphQLClient,\n options: {\n /** Identifier update input */\n input: IdentifierInput;\n /** Data subject lookup by name */\n dataSubjectsByName: { [k in string]: DataSubject };\n /** Existing identifier Id */\n identifierId: string;\n /** When true, skip publishing to privacy center */\n skipPublish?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const {\n input: identifier,\n dataSubjectsByName,\n identifierId,\n skipPublish = false,\n logger = NOOP_LOGGER,\n } = options;\n await makeGraphQLRequest(client, UPDATE_IDENTIFIER, {\n variables: {\n input: {\n id: identifierId,\n selectOptions: identifier.selectOptions,\n isRequiredInForm: identifier.isRequiredInForm,\n regex: identifier.regex,\n placeholder: identifier.placeholder,\n displayTitle: identifier.displayTitle,\n displayDescription: identifier.displayDescription,\n displayOrder: identifier.displayOrder,\n isUniqueOnPreferenceStore: identifier.isUniqueOnPreferenceStore,\n privacyCenterVisibility: identifier.privacyCenterVisibility,\n dataSubjectIds: identifier.dataSubjects\n ? identifier.dataSubjects.map((type) => dataSubjectsByName[type]!.id)\n : undefined,\n skipPublish,\n },\n },\n logger,\n });\n}\n","import { gql } from 'graphql-request';\n\nexport const ADD_SILO_DISCOVERY_RESULTS = gql`\n mutation AddSiloDiscoveryResults($pluginId: ID!, $rawResults: [SiloDiscoveryRawResultInput!]!) {\n addSiloDiscoveryResults(input: { pluginId: $pluginId, rawResults: $rawResults }) {\n success\n }\n }\n`;\n\nexport const ENABLED_PLUGINS = gql`\n query Plugins($dataSiloId: String!, $type: PluginType!) {\n plugins(filterBy: { dataSiloId: $dataSiloId, type: $type, enabled: true }) {\n plugins {\n id\n dataSilo {\n type\n }\n }\n totalCount\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { ENABLED_PLUGINS } from './gqls/siloDiscovery.js';\n\nexport interface Plugin {\n /** Associated data silo */\n dataSilo: {\n /** The type of plugin */\n type: string;\n };\n /** The ID of this plugin */\n id: string;\n}\n\nexport interface PluginResponse {\n /** The key object of the response */\n plugins: {\n /** The total count */\n totalCount: number;\n /** The list of plugins */\n plugins: Plugin[];\n };\n}\n\n/**\n * Fetch a data silo discovery plugin\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns An active data silo plugin (if multiple, returns the first)\n */\nexport async function fetchActiveSiloDiscoPlugin(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy: {\n /** The data silo to look up plugins for */\n dataSiloId: string;\n };\n },\n): Promise<Plugin> {\n const {\n logger = NOOP_LOGGER,\n filterBy: { dataSiloId },\n } = options;\n const response = await makeGraphQLRequest<PluginResponse>(client, ENABLED_PLUGINS, {\n variables: {\n dataSiloId,\n type: 'DATA_SILO_DISCOVERY',\n },\n logger,\n });\n\n const { plugins, totalCount } = response.plugins;\n if (totalCount === 0) {\n logger.error('No active data silo plugins found for this data silo.');\n process.exit(1);\n }\n\n return plugins[0]!;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\nexport const ACTIONS = gql`\n query TranscendCliActions($first: Int!, $offset: Int!) {\n actions(\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [{ field: type, direction: ASC }]\n ) {\n nodes {\n id\n type\n skipSecondaryIfNoFiles\n skipDownloadableStep\n requiresReview\n regionList\n regionDetectionMethod\n waitingPeriod\n }\n }\n }\n`;\n\nexport const UPDATE_ACTION = gql`\n mutation TranscendCliUpdateAction($input: UpdateActionInput!) {\n updateAction(input: $input) {\n clientMutationId\n }\n }\n`;\n","import {\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n RegionDetectionMethod,\n RequestAction,\n} from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { ACTIONS } from './gqls/action.js';\n\nexport interface Action {\n /** ID of identifier */\n id: string;\n /** Type of action */\n type: RequestAction;\n /** Whether to skip secondary when no files exist */\n skipSecondaryIfNoFiles: boolean;\n /** Whether to skip downloadable step */\n skipDownloadableStep: boolean;\n /** Whether action requires review */\n requiresReview: boolean;\n /** Waiting period for action */\n waitingPeriod: number;\n /** Method in which the data subject's region is detected */\n regionDetectionMethod: RegionDetectionMethod;\n /** The list of regions to show in the form */\n regionList: (IsoCountryCode | IsoCountrySubdivisionCode)[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all actions in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All actions in the organization\n */\nexport async function fetchAllActions(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Action[]> {\n const { logger } = options;\n const actions: Action[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n actions: { nodes },\n } = await makeGraphQLRequest<{\n /** Actions */\n actions: {\n /** List */\n nodes: Action[];\n };\n }>(client, ACTIONS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n actions.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return actions.sort((a, b) => a.type.localeCompare(b.type));\n}\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { ATTRIBUTE_KEYS_REQUESTS } from '../administration/gqls/attributeKey.js';\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\n\nexport interface AttributeKey {\n /** ID of attribute key */\n id: string;\n /** Name of attribute key */\n name: string;\n /** Attribute key type */\n type: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all attribute keys enabled for privacy requests\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All attribute keys in the organization\n */\nexport async function fetchAllRequestAttributeKeys(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<AttributeKey[]> {\n const { logger } = options;\n const attributeKeys: AttributeKey[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n attributeKeys: { nodes },\n } = await makeGraphQLRequest<{\n /** Query response */\n attributeKeys: {\n /** List of matches */\n nodes: AttributeKey[];\n };\n }>(client, ATTRIBUTE_KEYS_REQUESTS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n attributeKeys.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return attributeKeys.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\nexport const SILO_DISCOVERY_RESULTS = gql`\n query TranscendCliSiloDiscoveryResults($first: Int!, $offset: Int!) {\n siloDiscoveryResults(first: $first, offset: $offset) {\n nodes {\n title\n resourceId\n country\n countrySubDivision\n plaintextContext\n status\n containsSensitiveData\n suggestedCatalog {\n title\n }\n plugin {\n dataSilo {\n title\n }\n }\n }\n }\n }\n`;\n","import type { IsoCountryCode, IsoCountrySubdivisionCode } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { SILO_DISCOVERY_RESULTS } from './gqls/siloDiscoveryResult.js';\n\nexport interface SiloDiscoveryResult {\n /** Title of silo discovery result */\n title?: string;\n /** Resource ID of silo discovery result */\n resourceId: string;\n /** Suggested catalog */\n suggestedCatalog: {\n /** Title for the suggested catalog */\n title: string;\n };\n /** The likelihood that data is sensitive for this results */\n containsSensitiveData: string;\n /** The status of silo discovery triage */\n status: string;\n /** Hosting country of data silo discovery result */\n country?: IsoCountryCode;\n /** Hosting subdivision data silo discovery result */\n countrySubDivision?: IsoCountrySubdivisionCode;\n /** Plaintext context data silo discovery result */\n plaintextContext: string;\n /** The plugin that found this result */\n plugin: {\n /** The data silo the plugin belongs to */\n dataSilo: {\n /** The internal display title */\n title: string;\n };\n };\n}\n\nconst PAGE_SIZE = 30;\n\n/**\n * Fetch all silo discovery results in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All silo discovery results in the organization\n */\nexport async function fetchAllSiloDiscoveryResults(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<SiloDiscoveryResult[]> {\n const { logger } = options;\n const siloDiscoveryResults: SiloDiscoveryResult[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n siloDiscoveryResults: { nodes },\n } = await makeGraphQLRequest<{\n /** Discovery results */\n siloDiscoveryResults: {\n /** Nodes */\n nodes: SiloDiscoveryResult[];\n };\n }>(client, SILO_DISCOVERY_RESULTS, {\n variables: { first: PAGE_SIZE, offset, input: {}, filterBy: {} },\n logger,\n });\n\n const titledNodes = nodes.map((node) =>\n node.title === null && node.suggestedCatalog?.title\n ? { ...node, title: node.suggestedCatalog.title }\n : node,\n );\n\n siloDiscoveryResults.push(...titledNodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return siloDiscoveryResults;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const CATALOGS = gql`\n query TranscendCliCatalogs($first: Int!, $offset: Int!) {\n catalogs(first: $first, offset: $offset, filterBy: {}, useMaster: false) {\n nodes {\n integrationName\n title\n hasApiFunctionality\n }\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { CATALOGS } from './gqls/catalog.js';\n\nexport interface Catalog {\n /** Integration name */\n integrationName: string;\n /** Title of Data Silo */\n title: string;\n /** Whether API is supported */\n hasApiFunctionality: boolean;\n}\n\nconst PAGE_SIZE = 100;\n\n/**\n * Fetch all integration catalogs in an organization\n *\n * @param client - Client\n * @param options - Options\n * @returns Integration catalogs\n */\nexport async function fetchAllCatalogs(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Catalog[]> {\n const { logger } = options;\n const catalogs: Catalog[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n catalogs: { nodes },\n } = await makeGraphQLRequest<{\n /** integration catalogs */\n catalogs: {\n /** List */\n nodes: Catalog[];\n };\n }>(client, CATALOGS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n catalogs.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n return catalogs.sort((a, b) => a.integrationName.localeCompare(b.integrationName));\n}\n\nexport interface IndexedCatalogs {\n /** Mapping from service name to service title */\n serviceToTitle: { [k in string]: string };\n /** Mapping from service name to boolean indicate if service has API integration support */\n serviceToSupportedIntegration: { [k in string]: boolean };\n}\n\n/**\n * Fetch all integration catalogs and index them for usage in common utility manners\n *\n * @param client - Client\n * @param options - Options\n * @returns Integration catalogs\n */\nexport async function fetchAndIndexCatalogs(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<\n {\n /** List of all catalogs */\n catalogs: Catalog[];\n } & IndexedCatalogs\n> {\n const catalogs = await fetchAllCatalogs(client, options);\n\n const serviceToTitle = catalogs.reduce(\n (acc, catalog) => Object.assign(acc, { [catalog.integrationName]: catalog.title }),\n {} as { [k in string]: string },\n );\n\n const serviceToSupportedIntegration = catalogs.reduce(\n (acc, catalog) =>\n Object.assign(acc, {\n [catalog.integrationName]: catalog.hasApiFunctionality,\n }),\n {} as { [k in string]: boolean },\n );\n\n return {\n catalogs,\n serviceToTitle,\n serviceToSupportedIntegration,\n };\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const REQUEST_DATA_SILOS = gql`\n query TranscendCliRequestDataSilos(\n $first: Int!\n $offset: Int!\n $filterBy: RequestDataSiloFiltersInput!\n ) {\n requestDataSilos(\n filterBy: $filterBy\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [\n { field: createdAt, direction: DESC }\n { field: title, direction: ASC, model: dataSilo }\n ]\n ) {\n nodes {\n id\n request {\n type\n }\n }\n totalCount\n }\n }\n`;\n\nexport const CHANGE_REQUEST_DATA_SILO_STATUS = gql`\n mutation TranscendCliMarkRequestDataSiloCompleted(\n $requestDataSiloId: ID!\n $status: UpdateRequestDataSiloStatus!\n ) {\n changeRequestDataSiloStatus(input: { id: $requestDataSiloId, status: $status }) {\n requestDataSilo {\n id\n }\n }\n }\n`;\n\nexport const RETRY_REQUEST_DATA_SILO = gql`\n mutation TranscendCliRetryRequestDataSilo($requestDataSiloId: ID!) {\n retryRequestDataSilo(id: $requestDataSiloId) {\n requestDataSilo {\n id\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\n// orderBy: [\n// { field: createdAt, direction: DESC }\n// { field: title, direction: ASC, model: dataSilo }\n// ]\nexport const REDUCED_REQUESTS_FOR_DATA_SILO_COUNT = gql`\n query TranscendCliListReducedRequestsForDataSiloCount(\n $input: BulkCompletionReducedRequestInput!\n ) {\n listReducedRequestsForDataSilo(input: $input) {\n totalCount\n }\n }\n`;\n","import { RequestAction, RequestDataSiloStatus, RequestStatus } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { REQUEST_DATA_SILOS } from './gqls/requestDataSilo.js';\n\nexport interface RequestDataSilo {\n /** ID of RequestDataSilo */\n id: string;\n /** Request */\n request: {\n /** Type of request */\n type: RequestAction;\n };\n}\n\nexport interface RequestDataSiloFilters {\n /** ID of request to filter on */\n requestId?: string;\n /** Data silo ID */\n dataSiloId?: string;\n /** The statuses to filter on */\n statuses?: RequestDataSiloStatus[];\n /** The request statuses to filter on */\n requestStatuses?: RequestStatus[];\n}\n\n/**\n * Fetch a count of request data silos\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Count of request data silos\n */\nexport async function fetchRequestDataSilosCount(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: RequestDataSiloFilters;\n } = {},\n): Promise<number> {\n const { logger, filterBy: { requestId, dataSiloId, requestStatuses, statuses } = {} } = options;\n const {\n requestDataSilos: { totalCount },\n } = await makeGraphQLRequest<{\n /** Request Data Silos */\n requestDataSilos: {\n /** List */\n nodes: RequestDataSilo[];\n /** Total count */\n totalCount: number;\n };\n }>(client, REQUEST_DATA_SILOS, {\n variables: {\n first: 1,\n offset: 0,\n filterBy: {\n dataSiloId,\n requestId,\n status: statuses,\n requestStatus: requestStatuses,\n },\n },\n logger,\n });\n\n return totalCount;\n}\n\nconst PAGE_SIZE = 100;\n\n/**\n * Fetch all request data silos by some filter criteria\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns List of request data silos\n */\nexport async function fetchRequestDataSilos(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: RequestDataSiloFilters;\n /** Limit on number of requests */\n limit?: number;\n /** Handle progress updates */\n onProgress?: (numUpdated: number) => void;\n } = {},\n): Promise<RequestDataSilo[]> {\n const {\n logger,\n filterBy: { requestId, dataSiloId, requestStatuses, statuses } = {},\n limit,\n onProgress,\n } = options;\n const requestDataSilos: RequestDataSilo[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n requestDataSilos: { nodes },\n } = await makeGraphQLRequest<{\n /** Request Data Silos */\n requestDataSilos: {\n /** List */\n nodes: RequestDataSilo[];\n /** Total count */\n totalCount: number;\n };\n }>(client, REQUEST_DATA_SILOS, {\n variables: {\n first: PAGE_SIZE,\n offset,\n filterBy: {\n dataSiloId,\n requestId,\n status: statuses,\n requestStatus: requestStatuses,\n },\n },\n logger,\n });\n requestDataSilos.push(...nodes);\n\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n onProgress?.(nodes.length);\n } while (shouldContinue && (!limit || offset < limit));\n\n return requestDataSilos;\n}\n\n/**\n * Fetch a single request data silo by request and data silo IDs\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns The matching request data silo\n */\nexport async function fetchRequestDataSilo(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy: {\n /** ID of request to filter on */\n requestId: string;\n /** Data silo ID */\n dataSiloId: string;\n };\n },\n): Promise<RequestDataSilo> {\n const {\n logger,\n filterBy: { requestId, dataSiloId },\n } = options;\n const nodes = await fetchRequestDataSilos(client, {\n logger,\n filterBy: { requestId, dataSiloId },\n });\n if (nodes.length !== 1) {\n throw new Error(\n `Failed to find RequestDataSilo with requestId:${requestId},dataSiloId:${dataSiloId}`,\n );\n }\n\n return nodes[0]!;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const REQUEST_FILES = gql`\n query TranscendCliRequestFiles($first: Int!, $offset: Int!, $filterBy: RequestFileFiltersInput!) {\n requestFiles(\n filterBy: $filterBy\n first: $first\n offset: $offset\n orderBy: [{ field: createdAt, direction: ASC }, { field: id, direction: ASC }]\n ) {\n nodes {\n remoteId\n fileName\n }\n }\n }\n`;\n\nexport const BULK_REQUEST_FILES = gql`\n query TranscendCliBulkRequestFiles(\n $filterBy: BulkRequestFilesFiltersInput!\n $first: Int!\n $after: String\n ) {\n bulkRequestFiles(filterBy: $filterBy, first: $first, after: $after) {\n nodes {\n remoteId\n fileName\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { BULK_REQUEST_FILES } from './gqls/requestFile.js';\n\nexport interface RequestFileCursor {\n /** The ID of the request file */\n id: string;\n /** The created at timestamp */\n createdAt: string;\n}\n\nexport interface RequestFile {\n /** The remote ID */\n remoteId: string;\n /** The file name */\n fileName: string;\n}\n\nexport interface RequestFileResponse {\n /** RequestFiles */\n bulkRequestFiles: {\n /** List */\n nodes: RequestFile[];\n /** The page info */\n pageInfo: {\n /** Whether there is a next page */\n hasNextPage: boolean;\n /** The end cursor */\n endCursor: string;\n };\n };\n}\n\n/**\n * Fetch all RequestFiles for a single request\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All RequestFiles in the organization\n */\nexport async function fetchRequestFilesForRequest(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** How many request files to fetch per API call */\n pageSize?: number;\n /** Filter options */\n filterBy: {\n /** Filter by request IDs */\n requestIds: string[];\n /** Filter by data silo ID */\n dataSiloIds: string[];\n };\n },\n): Promise<RequestFile[]> {\n const { logger, pageSize = 100, filterBy } = options;\n const requestFiles: RequestFile[] = [];\n let cursor: string | null = null;\n\n let shouldContinue = false;\n do {\n const response: RequestFileResponse = await makeGraphQLRequest<RequestFileResponse>(\n client,\n BULK_REQUEST_FILES,\n {\n variables: {\n filterBy: {\n ...filterBy,\n },\n first: pageSize,\n after: cursor ?? undefined,\n },\n logger,\n },\n );\n const {\n bulkRequestFiles: { nodes, pageInfo },\n } = response;\n requestFiles.push(...nodes);\n shouldContinue = pageInfo.hasNextPage;\n cursor = pageInfo.endCursor;\n } while (shouldContinue);\n\n return requestFiles.sort((a, b) => a.remoteId.localeCompare(b.remoteId));\n}\n","export interface DataSiloAttributeValue {\n /** Key associated to value */\n attributeKey: {\n /** Name of key */\n name: string;\n };\n /** Name of value */\n name: string;\n}\n\nexport interface FormattedAttribute {\n /** Attribute key */\n key: string;\n /** Attribute values */\n values: string[];\n}\n\n/**\n * Format attribute value objects to key-pair values\n *\n * @param vals - Attribute values\n * @returns formatted attributes\n */\nexport function formatAttributeValues(vals: DataSiloAttributeValue[]): FormattedAttribute[] {\n const attributes: FormattedAttribute[] = [];\n\n vals.map((val) => {\n let foundKey = attributes.find((att) => att.key === val.attributeKey.name);\n\n if (foundKey === undefined) {\n foundKey = {\n key: val.attributeKey.name,\n values: [val.name],\n };\n attributes.push(foundKey);\n } else {\n foundKey.values.push(val.name);\n }\n return attributes;\n });\n\n return attributes;\n}\n","import { IsoCountryCode, IsoCountrySubdivisionCode } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { difference } from 'lodash-es';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { UPDATE_ACTION } from './gqls/action.js';\n\nconst ALL_COUNTRIES_AND_SUBDIVISIONS = [\n ...Object.values(IsoCountryCode),\n ...Object.values(IsoCountrySubdivisionCode),\n];\n\nexport interface SyncActionInput {\n /** Whether to skip secondary when no files exist */\n skipSecondaryIfNoFiles?: boolean;\n /** Whether to skip downloadable step */\n skipDownloadableStep?: boolean;\n /** Whether the request action requires review */\n requiresReview?: boolean;\n /** The wait period for the action */\n waitingPeriod?: number;\n /** The method in which the data subject's region is detected */\n regionDetectionMethod?: string;\n /** The list of regions to show in the form */\n regionList?: (IsoCountryCode | IsoCountrySubdivisionCode)[];\n /** The list of regions NOT to show in the form */\n regionBlockList?: (IsoCountryCode | IsoCountrySubdivisionCode)[];\n}\n\n/**\n * Sync the consent manager\n *\n * @param client - GraphQL client\n * @param actionInput - Action update details\n * @param options - Options\n */\nexport async function syncAction(\n client: GraphQLClient,\n actionInput: {\n /** Action update input */\n action: SyncActionInput;\n /** Existing action Id */\n actionId: string;\n /** When true, skip publishing to privacy center */\n skipPublish?: boolean;\n },\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n const { logger } = options;\n const { action, actionId, skipPublish = false } = actionInput;\n await makeGraphQLRequest(client, UPDATE_ACTION, {\n variables: {\n input: {\n id: actionId,\n skipSecondaryIfNoFiles: action.skipSecondaryIfNoFiles,\n skipDownloadableStep: action.skipDownloadableStep,\n requiresReview: action.requiresReview,\n waitingPeriod: action.waitingPeriod,\n skipPublish,\n regionList: action.regionBlockList\n ? difference(ALL_COUNTRIES_AND_SUBDIVISIONS, action.regionBlockList)\n : action.regionList,\n regionDetectionMethod: action.regionDetectionMethod,\n },\n },\n logger,\n });\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const TEMPLATES = gql`\n query TranscendCliTemplates($title: String, $first: Int!, $offset: Int!) {\n templates(filterBy: { text: $title }, first: $first, offset: $offset, useMaster: false) {\n nodes {\n id\n title\n subject {\n defaultMessage\n }\n template {\n defaultMessage\n }\n }\n }\n }\n`;\n\nexport const CREATE_TEMPLATE = gql`\n mutation TranscendCliCreateTemplate($title: String!) {\n createTemplate(input: { title: $title, template: \"\", subject: $title }) {\n clientMutationId\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { TEMPLATES, CREATE_TEMPLATE } from './gqls/template.js';\n\nexport interface Template {\n /** ID of Template */\n id: string;\n /** Title of Template */\n title: string;\n /** Template subject (e.g. email subject) */\n subject: {\n /** Default message for template subject */\n defaultMessage: string;\n };\n /** Template body - rich text HTML */\n template: {\n /** Default message for template body */\n defaultMessage: string;\n };\n}\n\nexport interface SyncTemplateInput {\n /** The title of the template */\n title: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all Templates in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All Templates in the organization\n */\nexport async function fetchAllTemplates(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** Filter by title */\n title?: string;\n };\n } = {},\n): Promise<Template[]> {\n const { logger, filterBy: { title } = {} } = options;\n const templates: Template[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n templates: { nodes },\n } = await makeGraphQLRequest<{\n /** Query response */\n templates: {\n /** List of matches */\n nodes: Template[];\n };\n }>(client, TEMPLATES, {\n variables: { first: PAGE_SIZE, offset, title },\n logger,\n });\n templates.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return templates.sort((a, b) => a.title.localeCompare(b.title));\n}\n\n/**\n * Sync an email template configuration\n *\n * @param client - GraphQL client\n * @param template - The email template input\n * @param options - Options\n */\nexport async function syncTemplate(\n client: GraphQLClient,\n template: SyncTemplateInput,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n const { logger } = options;\n const matches = await fetchAllTemplates(client, {\n logger,\n filterBy: { title: template.title },\n });\n const existingTemplate = matches.find(({ title }) => title === template.title);\n\n if (!existingTemplate) {\n await makeGraphQLRequest(client, CREATE_TEMPLATE, {\n variables: { title: template.title },\n logger,\n });\n }\n}\n","import { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { ADD_SILO_DISCOVERY_RESULTS } from './gqls/siloDiscovery.js';\n\nexport interface SiloDiscoveryRawResult {\n /** The name of the potential data silo entry */\n name: string;\n /** A unique UUID (represents the same resource across different silo discovery runs) */\n resourceId: string;\n /** Any hosts associated with the entry */\n host?: string;\n /** Type of data silo */\n type?: string | undefined;\n}\n\nconst CHUNK_SIZE = 1000;\n\n/**\n * Uploads silo discovery results for Transcend to classify\n *\n * @param client - GraphQL Client\n * @param options - Options\n */\nexport async function uploadSiloDiscoveryResults(\n client: GraphQLClient,\n options: {\n /** Plugin ID to associate with the results */\n pluginId: string;\n /** The discovery results to upload */\n results: SiloDiscoveryRawResult[];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { pluginId, results, logger = NOOP_LOGGER } = options;\n const chunks = chunk(results, CHUNK_SIZE);\n\n await mapSeries(chunks, async (rawResults) => {\n await makeGraphQLRequest<{\n /** Whether we successfully uploaded the results */\n success: boolean;\n }>(client, ADD_SILO_DISCOVERY_RESULTS, {\n variables: { pluginId, rawResults },\n logger,\n });\n });\n}\n","import { gql } from 'graphql-request';\n\nexport const REPORT_PROMPT_RUN = gql`\n mutation TranscendCliReportPromptRun($input: ReportPromptRunInput!) {\n reportPromptRun(input: $input) {\n clientMutationId\n promptRun {\n id\n }\n }\n }\n`;\n\nexport const ADD_MESSAGES_TO_PROMPT_RUN = gql`\n mutation TranscendCliAddMessagesToPromptRun($input: AddMessagesToPromptRunInput!) {\n addMessagesToPromptRun(input: $input) {\n clientMutationId\n promptRun {\n id\n }\n }\n }\n`;\n","import { QueueStatus, ChatCompletionRole } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { ADD_MESSAGES_TO_PROMPT_RUN } from './gqls/promptRun.js';\n\nexport interface AddMessagesToPromptRunInput {\n /** ID of run */\n promptRunId:\n | {\n /** Report by prompt run name */\n name: string;\n /** Don't report by ID */\n id?: undefined;\n }\n | {\n /** Don't report by name */\n name?: undefined;\n /** Report by prompt run ID */\n id: string;\n };\n /** Messages to report on */\n promptRunMessages?: {\n /** Message reported */\n content: string;\n /** Role of message */\n role: ChatCompletionRole;\n /** Template used if created from prompt */\n template?: string;\n }[];\n /** Error message (if one exists) */\n error?: string;\n /** The status of the run */\n status?: QueueStatus;\n /** Duration of time that it took to execute the prompt */\n duration?: number;\n}\n\n/**\n * Record a new prompt run\n *\n * @param client - GraphQL client\n * @param input - Prompt input\n * @param options - Options\n * @returns Prompt ID\n */\nexport async function addMessagesToPromptRun(\n client: GraphQLClient,\n { promptRunId, promptRunMessages = [], ...rest }: AddMessagesToPromptRunInput,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<string> {\n const { logger } = options;\n const {\n addMessagesToPromptRun: { promptRun },\n } = await makeGraphQLRequest<{\n /** addMessagesToPromptRun mutation */\n addMessagesToPromptRun: {\n /** Prompt */\n promptRun: {\n /** ID */\n id: string;\n };\n };\n }>(client, ADD_MESSAGES_TO_PROMPT_RUN, {\n variables: {\n input: {\n ...rest,\n ...promptRunId,\n promptRunMessages: promptRunMessages.map(({ content, ...rest }) => ({\n ...rest,\n message: content,\n })),\n },\n },\n logger,\n });\n return promptRun.id;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const AGENT_FILES = gql`\n query TranscendCliAgentFiles($first: Int!, $offset: Int!, $filterBy: AgentFileFiltersInput) {\n agentFiles(\n first: $first\n offset: $offset\n filterBy: $filterBy\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n description\n fileId\n size\n purpose\n initialFileName\n }\n }\n }\n`;\n\nexport const CREATE_AGENT_FILE = gql`\n mutation TranscendCliCreateAgentFile($input: CreateAgentFileInput!) {\n createAgentFile(input: $input) {\n agentFile {\n id\n name\n fileId\n initialFileName\n }\n }\n }\n`;\n\nexport const UPDATE_AGENT_FILES = gql`\n mutation TranscendCliUpdateAgentFiles($input: UpdateAgentFilesInput!) {\n updateAgentFiles(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { PromptFilePurpose } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { AGENT_FILES } from './gqls/agentFile.js';\n\nexport interface AgentFile {\n /** ID of agentFile */\n id: string;\n /** Name of agentFile */\n name: string;\n /** Description of the agentFile */\n description: string;\n /** Initial file name, useful to track if a file was split into multiple chunks */\n initialFileName?: string;\n /** File ID */\n fileId: string;\n /** File size */\n size: number;\n /** File purpose */\n purpose: PromptFilePurpose;\n}\n\nexport interface AgentFileFilterBy {\n /** Filter by remote file IDs */\n fileIds?: string[];\n /** Filter by file names */\n names?: string[];\n /** Filter by initial file names (when split into chunks) */\n initialFileNames?: string[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all agent files in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All agent files in the organization\n */\nexport async function fetchAllAgentFiles(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter by */\n filterBy?: AgentFileFilterBy;\n } = {},\n): Promise<AgentFile[]> {\n const { logger, filterBy = {} } = options;\n const agentFiles: AgentFile[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n agentFiles: { nodes },\n } = await makeGraphQLRequest<{\n /** AgentFiles */\n agentFiles: {\n /** List */\n nodes: AgentFile[];\n };\n }>(client, AGENT_FILES, {\n variables: { first: PAGE_SIZE, offset, filterBy },\n logger,\n });\n agentFiles.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return agentFiles.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const AGENT_FUNCTIONS = gql`\n query TranscendCliAgentFunctions($first: Int!, $offset: Int!) {\n agentFunctions(\n first: $first\n offset: $offset\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n description\n parameters\n }\n }\n }\n`;\n\nexport const CREATE_AGENT_FUNCTION = gql`\n mutation TranscendCliCreateAgentFunction($input: CreateAgentFunctionInput!) {\n createAgentFunction(input: $input) {\n agentFunction {\n id\n name\n }\n }\n }\n`;\n\nexport const UPDATE_AGENT_FUNCTIONS = gql`\n mutation TranscendCliUpdateAgentFunctions($input: UpdateAgentFunctionsInput!) {\n updateAgentFunctions(input: $input) {\n clientMutationId\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport type { JSONSchema7 } from 'json-schema';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { AGENT_FUNCTIONS } from './gqls/agentFunction.js';\n\nexport interface AgentFunction {\n /** ID of agentFunction */\n id: string;\n /** Name of agentFunction */\n name: string;\n /** Description of the agentFunction */\n description: string;\n /** The JSON schema */\n parameters: JSONSchema7;\n}\n\ninterface AgentFunctionRaw extends Omit<AgentFunction, 'parameters'> {\n /** Stringified parameters */\n parameters: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all agent functions in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All agent functions in the organization\n */\nexport async function fetchAllAgentFunctions(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<AgentFunction[]> {\n const { logger } = options;\n const agentFunctions: AgentFunction[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n agentFunctions: { nodes },\n } = await makeGraphQLRequest<{\n /** AgentFunctions */\n agentFunctions: {\n /** List */\n nodes: AgentFunctionRaw[];\n };\n }>(client, AGENT_FUNCTIONS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n agentFunctions.push(\n ...nodes.map((node) => ({\n ...node,\n parameters: JSON.parse(node.parameters),\n })),\n );\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return agentFunctions.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const AGENTS = gql`\n query TranscendCliAgents($first: Int!, $offset: Int!, $filterBy: AgentFiltersInput) {\n agents(\n first: $first\n offset: $offset\n filterBy: $filterBy\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n agentId\n instructions\n description\n codeInterpreterEnabled\n retrievalEnabled\n prompt {\n title\n }\n largeLanguageModel {\n name\n client\n }\n teams {\n name\n }\n owners {\n email\n }\n agentFunctions {\n name\n }\n agentFiles {\n name\n }\n }\n }\n }\n`;\n\nexport const CREATE_AGENT = gql`\n mutation TranscendCliCreateAgent($input: CreateAgentInput!) {\n createAgent(input: $input) {\n agent {\n id\n name\n agentId\n }\n }\n }\n`;\n\nexport const UPDATE_AGENTS = gql`\n mutation TranscendCliUpdateAgents($input: UpdateAgentsInput!) {\n updateAgents(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { LargeLanguageModelClient } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { AGENTS } from './gqls/agent.js';\n\nexport interface Agent {\n /** ID of agent */\n id: string;\n /** Name of agent */\n name: string;\n /** Agent instructions */\n instructions: string;\n /** The ID of the agent */\n agentId: string;\n /** Description of the agent */\n description: string;\n /** Whether the agent has code interpreter enabled */\n codeInterpreterEnabled: boolean;\n /** Whether the agent has retrieval enabled */\n retrievalEnabled: boolean;\n /** The prompt that the agent is based on */\n prompt?: {\n /** Title of the prompt */\n title: string;\n };\n /** Large language model that the agent is based on */\n largeLanguageModel: {\n /** Name of model */\n name: string;\n /** Client */\n client: LargeLanguageModelClient;\n };\n /** Teams assigned to the agent */\n teams: {\n /** Team name */\n name: string;\n }[];\n /** Users assigned to the agent */\n owners: {\n /** User email */\n email: string;\n }[];\n /** Functions that the agent has access to */\n agentFunctions: {\n /** Function name */\n name: string;\n }[];\n /** Files that the agent has access to */\n agentFiles: {\n /** File name */\n name: string;\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all agents in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All agents in the organization\n */\nexport async function fetchAllAgents(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter by */\n filterBy?: {\n /** Names of the agents to filter for */\n names?: string[];\n /** IDs of agents */\n agentIds?: string[];\n };\n } = {},\n): Promise<Agent[]> {\n const { logger, filterBy = {} } = options;\n const agents: Agent[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n agents: { nodes },\n } = await makeGraphQLRequest<{\n /** Agents */\n agents: {\n /** List */\n nodes: Agent[];\n };\n }>(client, AGENTS, {\n variables: { first: PAGE_SIZE, offset, filterBy },\n logger,\n });\n agents.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return agents.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const LARGE_LANGUAGE_MODELS = gql`\n query TranscendCliLargeLanguageModels(\n $first: Int!\n $offset: Int!\n $filterBy: LargeLanguageModelFiltersInput\n ) {\n largeLanguageModels(\n first: $first\n orderBy: [\n { field: name, direction: ASC }\n { field: client, direction: ASC }\n { field: isTranscendHosted, direction: ASC }\n ]\n offset: $offset\n filterBy: $filterBy\n ) {\n nodes {\n id\n name\n client\n isTranscendHosted\n }\n }\n }\n`;\n","import { LargeLanguageModelClient } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { LARGE_LANGUAGE_MODELS } from './gqls/largeLanguageModel.js';\n\nexport interface LargeLanguageModel {\n /** ID of prompts */\n id: string;\n /** The name of the large language model. */\n name: string;\n /** The content of the prompt template. */\n client: LargeLanguageModelClient;\n /** Whether hosted by Transcend or not */\n isTranscendHosted: boolean;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all LargeLanguageModels in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All LargeLanguageModels in the organization\n */\nexport async function fetchAllLargeLanguageModels(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<LargeLanguageModel[]> {\n const { logger } = options;\n const largeLanguageModels: LargeLanguageModel[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n largeLanguageModels: { nodes },\n } = await makeGraphQLRequest<{\n /** LargeLanguageModels */\n largeLanguageModels: {\n /** List */\n nodes: LargeLanguageModel[];\n };\n }>(client, LARGE_LANGUAGE_MODELS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n largeLanguageModels.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return largeLanguageModels.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const PROMPTS = gql`\n query TranscendCliPrompts($first: Int!, $offset: Int!, $filterBy: PromptFiltersInput) {\n prompts(\n first: $first\n orderBy: [{ field: title, direction: ASC }]\n offset: $offset\n filterBy: $filterBy\n ) {\n nodes {\n id\n title\n status\n content\n temperature\n topP\n maxTokensToSample\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\n// orderBy: [{ field: title, direction: ASC }]\nexport const PROMPT_PARTIALS = gql`\n query TranscendCliPromptPartials($first: Int!, $offset: Int!) {\n promptPartials(first: $first, offset: $offset) {\n nodes {\n id\n title\n content\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\n// orderBy: [{ field: title, direction: ASC }]\nexport const PROMPT_GROUPS = gql`\n query TranscendCliPromptGroups($first: Int!, $offset: Int!) {\n promptGroups(first: $first, offset: $offset) {\n nodes {\n id\n title\n description\n prompts {\n title\n }\n }\n }\n }\n`;\n\nexport const PROMPTS_WITH_VARIABLES = gql`\n query TranscendCliPromptsWithVariables($input: PromptsWithVariablesInput!) {\n promptsWithVariables(input: $input) {\n prompts {\n id\n title\n content\n status\n temperature\n topP\n maxTokensToSample\n responseFormat\n }\n promptPartials {\n id\n title\n content\n slug\n }\n calculatedVariables {\n data\n name\n }\n runtimeVariables {\n name\n }\n }\n }\n`;\n\nexport const UPDATE_PROMPTS = gql`\n mutation TranscendCliUpdatePrompts($input: UpdatePromptsInput!) {\n updatePrompts(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const CREATE_PROMPT = gql`\n mutation TranscendCliCreatePrompt($input: CreatePromptInput!) {\n createPrompt(input: $input) {\n clientMutationId\n prompt {\n id\n }\n }\n }\n`;\n\nexport const UPDATE_PROMPT_PARTIALS = gql`\n mutation TranscendCliUpdatePromptPartials($input: UpdatePromptPartialsInput!) {\n updatePromptPartials(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const CREATE_PROMPT_PARTIAL = gql`\n mutation TranscendCliCreatePromptPartial($input: CreatePromptPartialInput!) {\n createPromptPartial(input: $input) {\n clientMutationId\n promptPartial {\n id\n }\n }\n }\n`;\n\nexport const UPDATE_PROMPT_GROUPS = gql`\n mutation TranscendCliUpdatePromptGroups($input: UpdatePromptGroupsInput!) {\n updatePromptGroups(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const CREATE_PROMPT_GROUP = gql`\n mutation TranscendCliCreatePromptPartial($input: CreatePromptGroupInput!) {\n createPromptGroup(input: $input) {\n clientMutationId\n promptGroup {\n id\n }\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PROMPT_GROUPS } from './gqls/prompt.js';\n\nexport interface PromptGroup {\n /** ID of prompts */\n id: string;\n /** The title of the prompt group. */\n title: string;\n /** The description of the prompt group. */\n description: string;\n /** Prompts in the group */\n prompts: {\n /** Title of prompt */\n title: string;\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all PromptGroups in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All PromptGroups in the organization\n */\nexport async function fetchAllPromptGroups(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<PromptGroup[]> {\n const { logger } = options;\n const promptGroups: PromptGroup[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n promptGroups: { nodes },\n } = await makeGraphQLRequest<{\n /** PromptGroups */\n promptGroups: {\n /** List */\n nodes: PromptGroup[];\n };\n }>(client, PROMPT_GROUPS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n promptGroups.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return promptGroups.sort((a, b) => a.title.localeCompare(b.title));\n}\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PROMPT_PARTIALS } from './gqls/prompt.js';\n\nexport interface PromptPartial {\n /** ID of prompts */\n id: string;\n /** The title of the prompt partial. */\n title: string;\n /** The content of the prompt partial. */\n content: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all PromptPartials in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All PromptPartials in the organization\n */\nexport async function fetchAllPromptPartials(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<PromptPartial[]> {\n const { logger } = options;\n const promptPartials: PromptPartial[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n promptPartials: { nodes },\n } = await makeGraphQLRequest<{\n /** PromptPartials */\n promptPartials: {\n /** List */\n nodes: PromptPartial[];\n };\n }>(client, PROMPT_PARTIALS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n promptPartials.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return promptPartials.sort((a, b) => a.title.localeCompare(b.title));\n}\n","import { PromptStatus, PromptResponseFormat } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PROMPTS, PROMPTS_WITH_VARIABLES } from './gqls/prompt.js';\n\nexport interface Prompt {\n /** ID of prompt */\n id: string;\n /** The title of the prompt */\n title: string;\n /** The status of the prompt */\n status: PromptStatus;\n /** The content of the prompt */\n content: string;\n /** Temperature to use with prompt */\n temperature: number;\n /** Top P to use with prompt */\n topP: number;\n /** Max tokens to sample for prompt */\n maxTokensToSample: number;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all Prompts in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All Prompts in the organization\n */\nexport async function fetchAllPrompts(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** Filter by text */\n text?: string;\n /** Filter by ids */\n ids?: string[];\n /** Filter by titles */\n titles?: string[];\n };\n } = {},\n): Promise<Prompt[]> {\n const { logger, filterBy: { text, ids = [], titles = [] } = {} } = options;\n const prompts: Prompt[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n prompts: { nodes },\n } = await makeGraphQLRequest<{\n /** Prompts */\n prompts: {\n /** List */\n nodes: Prompt[];\n };\n }>(client, PROMPTS, {\n variables: {\n first: PAGE_SIZE,\n offset,\n filterBy: {\n ...(text ? { text } : {}),\n ...(titles.length > 0 ? { title: titles } : {}),\n ...(ids.length > 0 ? { id: ids } : {}),\n },\n },\n logger,\n });\n prompts.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return prompts.sort((a, b) => a.title.localeCompare(b.title));\n}\n\n/**\n * The basic metadata needed to use a prompt at runtime\n */\nexport type TranscendPromptTemplated = {\n /** ID of prompt */\n id: string;\n /** Title of prompt */\n title: string;\n /** Content of prompt */\n content: string;\n /** Status of prompt */\n status: PromptStatus;\n /** Temperature */\n temperature?: number;\n /** Top P */\n topP?: number;\n /** Max tokens to sample */\n maxTokensToSample?: number;\n /** Response format */\n responseFormat?: PromptResponseFormat;\n};\n\n/**\n * The basic metadata needed to use a prompt partial at runtime\n */\nexport type TranscendPromptPartialTemplated = {\n /** ID of prompt */\n id: string;\n /** Title of prompt */\n title: string;\n /** Slug of prompt */\n slug: string;\n /** Content of prompt */\n content: string;\n};\n\n/**\n * Calculated variables\n */\nexport type PromptCalculatedVariable = {\n /** JSON stringified data to template */\n data: string | null;\n /** Name of variable */\n name: string;\n};\n\n/**\n * Runtime variables\n */\nexport type PromptRuntimeVariable = {\n /** Type of variable */\n type: string;\n /** Name of variable */\n name: string;\n};\n\n/**\n * Metadata useful for filling variables within a prompt\n */\nexport type TranscendPromptsAndVariables = {\n /** Prompts ready to be templated */\n prompts: TranscendPromptTemplated[];\n /** Prompt partials */\n promptPartials: TranscendPromptPartialTemplated[];\n /** Calculated variables to be templated */\n calculatedVariables: PromptCalculatedVariable[];\n /** Runtime variables to be templated */\n runtimeVariables: PromptRuntimeVariable[];\n};\n\n/**\n * Fetch prompts with templated variables\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Prompts and template variables\n */\nexport async function fetchPromptsWithVariables(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** Filter by prompt titles */\n titles?: string[];\n /** Filter by prompt ids */\n ids?: string[];\n };\n } = {},\n): Promise<TranscendPromptsAndVariables> {\n const { logger, filterBy: { titles: promptTitles = [], ids: promptIds = [] } = {} } = options;\n const { promptsWithVariables } = await makeGraphQLRequest<{\n /** Prompts */\n promptsWithVariables: TranscendPromptsAndVariables;\n }>(client, PROMPTS_WITH_VARIABLES, {\n variables: {\n input: {\n ...(promptTitles.length > 0 ? { promptTitles } : {}),\n ...(promptIds.length > 0 ? { promptIds } : {}),\n },\n },\n logger,\n });\n\n return promptsWithVariables;\n}\n","import { gql } from 'graphql-request';\n\nexport const PROMPT_THREADS = gql`\n query TranscendCliPromptThreads(\n $first: Int!\n $offset: Int!\n $filterBy: PromptThreadFiltersInput!\n ) {\n promptThreads(first: $first, offset: $offset, filterBy: $filterBy) {\n nodes {\n id\n threadId\n slackMessageTs\n slackTeamId\n slackChannelId\n slackChannelName\n }\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PROMPT_THREADS } from './gqls/promptThread.js';\n\nexport interface PromptThread {\n /** ID of prompts */\n id: string;\n /** Thread ID from API */\n threadId: string;\n /** Related slack message TS */\n slackMessageTs?: string;\n /** Related slack message team ID */\n slackTeamId?: string;\n /** Related slack channel ID */\n slackChannelId?: string;\n /** Related slack channel name */\n slackChannelName?: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all PromptThreads in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All PromptThreads in the organization\n */\nexport async function fetchAllPromptThreads(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy: {\n /** Thread IDs to filter on */\n threadIds?: string[];\n /** Slack message timestamps to filter on */\n slackMessageTs?: string[];\n };\n },\n): Promise<PromptThread[]> {\n const { logger, filterBy } = options;\n const promptThreads: PromptThread[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n promptThreads: { nodes },\n } = await makeGraphQLRequest<{\n /** PromptThreads */\n promptThreads: {\n /** List */\n nodes: PromptThread[];\n };\n }>(client, PROMPT_THREADS, {\n variables: { first: PAGE_SIZE, offset, filterBy },\n logger,\n });\n promptThreads.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return promptThreads.sort((a, b) => a.threadId.localeCompare(b.threadId));\n}\n","import {\n QueueStatus,\n ChatCompletionRole,\n PromptRunProductArea,\n LargeLanguageModelClient,\n} from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { REPORT_PROMPT_RUN } from './gqls/promptRun.js';\n\nexport interface ReportPromptRunInput {\n /** Name of run */\n name: string;\n /** The related product area being uploaded to */\n productArea: PromptRunProductArea;\n /** Messages reported on */\n promptRunMessages: {\n /** Message reported */\n content: string;\n /** Role of message */\n role: ChatCompletionRole;\n /** Template used if created from prompt */\n template?: string;\n }[];\n /** ID of the Transcend prompt being reported */\n promptId?: string;\n /** Title of the prompt being reported on */\n promptTitle?: string;\n /** Error message (if one exists) */\n error?: string;\n /** The status of the run */\n status?: QueueStatus;\n /** Employee email that is executing the request */\n runByEmployeeEmail?: string;\n /** Duration of time that it took to execute the prompt */\n duration?: number;\n /** Temperature used when running prompt */\n temperature?: number;\n /** TopP parameter used when running prompt */\n topP?: number;\n /** Max tokens ot sample parameter used when running prompt */\n maxTokensToSample?: number;\n /** The ID of the prompt group being reported */\n promptGroupId?: string;\n /** The title of the prompt group being reported */\n promptGroupTitle?: string;\n /** The LLM Id being reported on */\n largeLanguageModelId?: string;\n /** The name of the large language model being reported on */\n largeLanguageModelName?: string;\n /** The name of the large language model client reported on */\n largeLanguageModelClient?: LargeLanguageModelClient;\n /** ID of the application calling pathfinder */\n applicationId?: string;\n /** Name of the application calling pathfinder */\n applicationName?: string;\n /** Name of the code package calling pathfinder */\n codePackageName?: string;\n /** Name of the repository calling pathfinder */\n repositoryName?: string;\n /** ID of the pathfinder applying policies */\n pathfinderId?: string;\n /** Name of the pathfinder applying policies */\n pathfinderName?: string;\n /** Core identifier of the application user being reported on */\n applicationUserCoreIdentifier?: string;\n /** Name of the application user being reported on */\n applicationUserName?: string;\n}\n\n/**\n * Record a new prompt run\n *\n * @param client - GraphQL client\n * @param input - Prompt input\n * @param options - Options\n * @returns Prompt ID\n */\nexport async function reportPromptRun(\n client: GraphQLClient,\n input: ReportPromptRunInput,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<string> {\n const { logger } = options;\n const {\n reportPromptRun: { promptRun },\n } = await makeGraphQLRequest<{\n /** reportPromptRun mutation */\n reportPromptRun: {\n /** Prompt */\n promptRun: {\n /** ID */\n id: string;\n };\n };\n }>(client, REPORT_PROMPT_RUN, {\n variables: {\n input: {\n ...input,\n promptRunMessages: input.promptRunMessages.map(({ content, ...rest }) => ({\n ...rest,\n message: content,\n })),\n },\n },\n logger,\n });\n return promptRun.id;\n}\n","import { PromptFilePurpose } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllAgentFiles, type AgentFile } from './fetchAllAgentFiles.js';\nimport { UPDATE_AGENT_FILES, CREATE_AGENT_FILE } from './gqls/agentFile.js';\n\nexport interface AgentFileInput {\n /** Name of the agent file */\n name: string;\n /** Description of the agent file */\n description?: string;\n /** File ID */\n fileId: string;\n /** File size */\n size: number;\n /** File purpose */\n purpose: PromptFilePurpose;\n}\n\n/**\n * Create a new agent file\n *\n * @param client - GraphQL client\n * @param agentFile - Input\n * @param options - Options\n * @returns Created agent file\n */\nexport async function createAgentFile(\n client: GraphQLClient,\n options: {\n /** Agent file to create */\n input: AgentFileInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<AgentFile, 'id' | 'name' | 'fileId'>> {\n const { input: agentFile, logger = NOOP_LOGGER } = options;\n const input = {\n name: agentFile.name,\n description: agentFile.description,\n fileId: agentFile.fileId,\n size: agentFile.size,\n purpose: agentFile.purpose,\n fileUploadedAt: new Date(),\n agentIds: [],\n // TODO: https://transcend.height.app/T-31994 - sync agents\n };\n\n const { createAgentFile } = await makeGraphQLRequest<{\n /** Create agent file mutation */\n createAgentFile: {\n /** Created agent file */\n agentFile: AgentFile;\n };\n }>(client, CREATE_AGENT_FILE, {\n variables: { input },\n logger,\n });\n return createAgentFile.agentFile;\n}\n\n/**\n * Update agent files\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateAgentFiles(\n client: GraphQLClient,\n options: {\n /** [AgentFileInput, agentFileId] list */\n input: [AgentFileInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: agentFiles, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_AGENT_FILES, {\n variables: {\n input: {\n agentFiles: agentFiles.map(([agentFile, id]) => ({\n id,\n name: agentFile.name,\n description: agentFile.description,\n fileId: agentFile.fileId,\n size: agentFile.size,\n purpose: agentFile.purpose,\n })),\n },\n },\n logger,\n });\n}\n\n/**\n * Sync the agent files\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncAgentFiles(\n client: GraphQLClient,\n inputs: AgentFileInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n logger.info(`Syncing \"${inputs.length}\" agent files...`);\n\n let encounteredError = false;\n\n const existingAgentFiles = await fetchAllAgentFiles(client, { logger });\n\n const agentFileByName = keyBy(existingAgentFiles, 'name') as {\n [k in string]: Pick<AgentFile, 'id' | 'name' | 'fileId'>;\n };\n\n const newAgentFiles = inputs.filter((input) => !agentFileByName[input.name]);\n\n await mapSeries(newAgentFiles, async (agentFile) => {\n try {\n const newAgentFile = await createAgentFile(client, { input: agentFile, logger });\n agentFileByName[newAgentFile.name] = newAgentFile;\n logger.info(`Successfully synced agent file \"${agentFile.name}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync agent file \"${agentFile.name}\"! - ${(err as Error).message}`);\n }\n });\n\n try {\n logger.info(`Updating \"${inputs.length}\" agent files!`);\n await updateAgentFiles(client, {\n input: inputs.map((input) => [input, agentFileByName[input.name]!.id]),\n logger,\n });\n logger.info(`Successfully synced \"${inputs.length}\" agent files!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync \"${inputs.length}\" agent files! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport type { JSONSchema7 } from 'json-schema';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllAgentFunctions, type AgentFunction } from './fetchAllAgentFunctions.js';\nimport { UPDATE_AGENT_FUNCTIONS, CREATE_AGENT_FUNCTION } from './gqls/agentFunction.js';\n\nexport interface AgentFunctionInput {\n /** Name of the agent function */\n name: string;\n /** Description of the agent function */\n description: string;\n /** The JSON schema parameters (string or parsed) */\n parameters: JSONSchema7 | string;\n}\n\n/**\n * Create a new agent function\n *\n * @param client - GraphQL client\n * @param agentFunction - Input\n * @param options - Options\n * @returns Created agent function\n */\nexport async function createAgentFunction(\n client: GraphQLClient,\n options: {\n /** Agent function to create */\n input: AgentFunctionInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<AgentFunction, 'id' | 'name'>> {\n const { input: agentFunction, logger = NOOP_LOGGER } = options;\n const input = {\n name: agentFunction.name,\n description: agentFunction.description,\n parameters: agentFunction.parameters,\n agentIds: [],\n // TODO: https://transcend.height.app/T-31994 - sync agents\n };\n\n const { createAgentFunction } = await makeGraphQLRequest<{\n /** Create agent function mutation */\n createAgentFunction: {\n /** Created agent function */\n agentFunction: AgentFunction;\n };\n }>(client, CREATE_AGENT_FUNCTION, {\n variables: { input },\n logger,\n });\n return createAgentFunction.agentFunction;\n}\n\n/**\n * Update agent functions\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateAgentFunctions(\n client: GraphQLClient,\n options: {\n /** [AgentFunctionInput, agentFunctionId] list */\n input: [AgentFunctionInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: agentFunctions, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_AGENT_FUNCTIONS, {\n variables: {\n input: {\n agentFunctions: agentFunctions.map(([agentFunction, id]) => ({\n id,\n name: agentFunction.name,\n description: agentFunction.description,\n parameters: agentFunction.parameters,\n })),\n },\n },\n logger,\n });\n}\n\n/**\n * Sync the agent functions\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncAgentFunctions(\n client: GraphQLClient,\n inputs: AgentFunctionInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n logger.info(`Syncing \"${inputs.length}\" agent functions...`);\n\n let encounteredError = false;\n\n const existingAgentFunctions = await fetchAllAgentFunctions(client, { logger });\n\n const agentFunctionByName = keyBy(existingAgentFunctions, 'name') as {\n [k in string]: Pick<AgentFunction, 'id' | 'name'>;\n };\n\n const newAgentFunctions = inputs.filter((input) => !agentFunctionByName[input.name]);\n\n await mapSeries(newAgentFunctions, async (agentFunction) => {\n try {\n const newAgentFunction = await createAgentFunction(client, { input: agentFunction, logger });\n agentFunctionByName[newAgentFunction.name] = newAgentFunction;\n logger.info(`Successfully synced agent function \"${agentFunction.name}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to sync agent function \"${agentFunction.name}\"! - ${(err as Error).message}`,\n );\n }\n });\n\n try {\n logger.info(`Updating \"${inputs.length}\" agent functions!`);\n await updateAgentFunctions(client, {\n input: inputs.map((input) => [input, agentFunctionByName[input.name]!.id]),\n logger,\n });\n logger.info(`Successfully synced \"${inputs.length}\" agent functions!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync \"${inputs.length}\" agent functions! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import { LargeLanguageModelClient } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllAgents, type Agent } from './fetchAllAgents.js';\nimport { UPDATE_AGENTS, CREATE_AGENT } from './gqls/agent.js';\n\nexport interface AgentInput {\n /** Name of the agent */\n name: string;\n /** Description of the agent */\n description?: string;\n /** Whether the agent has code interpreter enabled */\n codeInterpreterEnabled?: boolean;\n /** Whether the agent has retrieval enabled */\n retrievalEnabled?: boolean;\n /** The prompt title */\n prompt?: string;\n /** Large language model config */\n 'large-language-model': {\n /** Name of model */\n name: string;\n /** Client */\n client: LargeLanguageModelClient;\n };\n}\n\n/**\n * Create a new agent\n *\n * @param client - GraphQL client\n * @param agent - Input\n * @param options - Options\n * @returns Created agent\n */\nexport async function createAgent(\n client: GraphQLClient,\n options: {\n /** Agent to create */\n input: AgentInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<Agent, 'id' | 'name' | 'agentId'>> {\n const { input: agent, logger = NOOP_LOGGER } = options;\n const input = {\n name: agent.name,\n description: agent.description,\n codeInterpreterEnabled: agent.codeInterpreterEnabled,\n retrievalEnabled: agent.retrievalEnabled,\n promptTitle: agent.prompt,\n largeLanguageModelName: agent['large-language-model'].name,\n largeLanguageModelClient: agent['large-language-model'].client,\n // TODO: https://transcend.height.app/T-32760 - agentFunction, agentFile\n // TODO: https://transcend.height.app/T-31994 - owners and teams\n };\n\n const { createAgent } = await makeGraphQLRequest<{\n /** Create agent mutation */\n createAgent: {\n /** Created agent */\n agent: Agent;\n };\n }>(client, CREATE_AGENT, {\n variables: { input },\n logger,\n });\n return createAgent.agent;\n}\n\n/**\n * Update agents\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateAgents(\n client: GraphQLClient,\n options: {\n /** [AgentInput, agentId] list */\n input: [AgentInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: agents, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_AGENTS, {\n variables: {\n input: {\n agents: agents.map(([agent, id]) => ({\n id,\n name: agent.name,\n description: agent.description,\n codeInterpreterEnabled: agent.codeInterpreterEnabled,\n retrievalEnabled: agent.retrievalEnabled,\n // TODO: https://transcend.height.app/T-31995 - prompt, largeLanguageModel, agentFunction, agentFile\n })),\n },\n },\n logger,\n });\n}\n\n/**\n * Sync the agents\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncAgents(\n client: GraphQLClient,\n inputs: AgentInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n logger.info(`Syncing \"${inputs.length}\" agents...`);\n\n let encounteredError = false;\n\n const existingAgents = await fetchAllAgents(client, { logger });\n\n const agentByName = keyBy(existingAgents, 'name') as {\n [k in string]: Pick<Agent, 'id' | 'name' | 'agentId'>;\n };\n\n const newAgents = inputs.filter((input) => !agentByName[input.name]);\n\n await mapSeries(newAgents, async (agent) => {\n try {\n const newAgent = await createAgent(client, { input: agent, logger });\n agentByName[newAgent.name] = newAgent;\n logger.info(`Successfully synced agent \"${agent.name}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync agent \"${agent.name}\"! - ${(err as Error).message}`);\n }\n });\n\n try {\n logger.info(`Updating \"${inputs.length}\" agents!`);\n await updateAgents(client, {\n input: inputs.map((input) => [input, agentByName[input.name]!.id]),\n logger,\n });\n logger.info(`Successfully synced \"${inputs.length}\" agents!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync \"${inputs.length}\" agents! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import { map, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllPromptGroups } from './fetchPromptGroups.js';\nimport { fetchAllPrompts } from './fetchPrompts.js';\nimport { UPDATE_PROMPT_GROUPS, CREATE_PROMPT_GROUP } from './gqls/prompt.js';\n\nexport interface PromptGroupInput {\n /** Title of prompt group */\n title: string;\n /** Description */\n description: string;\n /** Prompt titles */\n prompts: string[];\n}\n\nexport interface EditPromptGroupInput {\n /** Title of prompt group */\n title: string;\n /** Prompt group description */\n description: string;\n /** Prompt IDs */\n promptIds: string[];\n}\n\n/**\n * Create a new prompt group\n *\n * @param client - GraphQL client\n * @param input - Prompt input\n * @param options - Options\n * @returns Prompt group ID\n */\nexport async function createPromptGroup(\n client: GraphQLClient,\n options: {\n /** Prompt group to create */\n input: EditPromptGroupInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<string> {\n const { input, logger = NOOP_LOGGER } = options;\n const {\n createPromptGroup: { promptGroup },\n } = await makeGraphQLRequest<{\n /** createPromptGroup mutation */\n createPromptGroup: {\n /** Prompt group */\n promptGroup: {\n /** ID */\n id: string;\n };\n };\n }>(client, CREATE_PROMPT_GROUP, {\n variables: { input },\n logger,\n });\n logger.info(`Successfully created prompt group \"${input.title}\"!`);\n return promptGroup.id;\n}\n\n/**\n * Update a set of existing prompt groups\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updatePromptGroups(\n client: GraphQLClient,\n options: {\n /** [EditPromptGroupInput, promptGroupId] list */\n input: [EditPromptGroupInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: promptGroups, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_PROMPT_GROUPS, {\n variables: {\n input: {\n promptGroups: promptGroups.map(([promptGroup, id]) => ({\n ...promptGroup,\n id,\n })),\n },\n },\n logger,\n });\n logger.info(`Successfully updated ${promptGroups.length} prompt groups!`);\n}\n\n/**\n * Sync the prompt groups\n *\n * @param client - GraphQL client\n * @param promptGroups - PromptGroups\n * @param options - Options\n * @returns True if synced successfully\n */\nexport async function syncPromptGroups(\n client: GraphQLClient,\n promptGroups: PromptGroupInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Concurrency */\n concurrency?: number;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER, concurrency = 20 } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${promptGroups.length}\" prompt groups...`);\n\n // Index existing prompt groups\n const existing = await fetchAllPromptGroups(client, { logger });\n const existingPrompts = await fetchAllPrompts(client, { logger });\n const promptByTitle = keyBy(existingPrompts, 'title');\n const promptGroupByTitle = keyBy(existing, 'title');\n\n // Determine which promptGroups are new vs existing\n const mapPromptGroupsToExisting = promptGroups.map((promptInput) => [\n promptInput,\n promptGroupByTitle[promptInput.title]?.id,\n ]);\n\n // Create the new promptGroups\n const newPromptGroups = mapPromptGroupsToExisting\n .filter(([, existing]) => !existing)\n .map(([promptInput]) => promptInput as PromptGroupInput);\n try {\n logger.info(`Creating \"${newPromptGroups.length}\" new prompt groups...`);\n await map(\n newPromptGroups,\n async (prompt) => {\n await createPromptGroup(client, {\n input: {\n ...prompt,\n promptIds: prompt.prompts.map((title) => {\n const prompt = promptByTitle[title];\n if (!prompt) {\n throw new Error(`Failed to find prompt with title: \"${title}\"`);\n }\n return prompt.id;\n }),\n },\n logger,\n });\n },\n {\n concurrency,\n },\n );\n logger.info(`Successfully synced ${newPromptGroups.length} prompt groups!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create prompt groups! - ${(err as Error).message}`);\n }\n\n // Update existing promptGroups\n const existingPromptGroupsMapped = mapPromptGroupsToExisting.filter(\n (x): x is [PromptGroupInput, string] => !!x[1],\n );\n try {\n logger.info(`Updating \"${existingPromptGroupsMapped.length}\" prompt groups...`);\n await updatePromptGroups(client, {\n input: existingPromptGroupsMapped.map(([{ prompts, ...input }, id]) => [\n {\n ...input,\n promptIds: prompts.map((title) => {\n const prompt = promptByTitle[title];\n if (!prompt) {\n throw new Error(`Failed to find prompt with title: \"${title}\"`);\n }\n return prompt.id;\n }),\n },\n id,\n ]),\n logger,\n });\n logger.info(`Successfully updated \"${existingPromptGroupsMapped.length}\" prompt groups!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create prompt groups! - ${(err as Error).message}`);\n }\n\n logger.info(`Synced \"${promptGroups.length}\" prompt groups!`);\n\n return !encounteredError;\n}\n","import { map, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllPromptPartials } from './fetchPromptPartials.js';\nimport { UPDATE_PROMPT_PARTIALS, CREATE_PROMPT_PARTIAL } from './gqls/prompt.js';\n\nexport interface PromptPartialInput {\n /** Title of prompt partial */\n title: string;\n /** Prompt partial content */\n content: string;\n}\n\n/**\n * Create a new prompt partial\n *\n * @param client - GraphQL client\n * @param input - Prompt input\n * @param options - Options\n * @returns Prompt partial ID\n */\nexport async function createPromptPartial(\n client: GraphQLClient,\n options: {\n /** Prompt partial to create */\n input: {\n /** Title of prompt partial */\n title: string;\n /** Prompt content */\n content: string;\n };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<string> {\n const { input, logger = NOOP_LOGGER } = options;\n const {\n createPromptPartial: { promptPartial },\n } = await makeGraphQLRequest<{\n /** createPromptPartial mutation */\n createPromptPartial: {\n /** Prompt partial */\n promptPartial: {\n /** ID */\n id: string;\n };\n };\n }>(client, CREATE_PROMPT_PARTIAL, {\n variables: { input },\n logger,\n });\n logger.info(`Successfully created prompt partial \"${input.title}\"!`);\n return promptPartial.id;\n}\n\n/**\n * Update a set of existing prompt partials\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updatePromptPartials(\n client: GraphQLClient,\n options: {\n /** [PromptPartialInput, promptPartialId] list */\n input: [PromptPartialInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: promptPartials, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_PROMPT_PARTIALS, {\n variables: {\n input: {\n promptPartials: promptPartials.map(([promptPartial, id]) => ({\n ...promptPartial,\n id,\n })),\n },\n },\n logger,\n });\n logger.info(`Successfully updated ${promptPartials.length} prompt partials!`);\n}\n\n/**\n * Sync the prompt partials\n *\n * @param client - GraphQL client\n * @param promptPartials - PromptPartials\n * @param options - Options\n * @returns True if synced successfully\n */\nexport async function syncPromptPartials(\n client: GraphQLClient,\n promptPartials: PromptPartialInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Concurrency */\n concurrency?: number;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER, concurrency = 20 } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${promptPartials.length}\" prompt partials...`);\n\n // Index existing prompt partials\n const existing = await fetchAllPromptPartials(client, { logger });\n const promptPartialByTitle = keyBy(existing, 'title');\n\n // Determine which promptPartials are new vs existing\n const mapPromptPartialsToExisting = promptPartials.map((promptInput) => [\n promptInput,\n promptPartialByTitle[promptInput.title]?.id,\n ]);\n\n // Create the new promptPartials\n const newPromptPartials = mapPromptPartialsToExisting\n .filter(([, existing]) => !existing)\n .map(([promptInput]) => promptInput as PromptPartialInput);\n try {\n logger.info(`Creating \"${newPromptPartials.length}\" new prompt partials...`);\n await map(\n newPromptPartials,\n async (prompt) => {\n await createPromptPartial(client, { input: prompt, logger });\n },\n {\n concurrency,\n },\n );\n logger.info(`Successfully synced ${newPromptPartials.length} prompt partials!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create prompt partials! - ${(err as Error).message}`);\n }\n\n // Update existing promptPartials\n const existingPromptPartials = mapPromptPartialsToExisting.filter(\n (x): x is [PromptPartialInput, string] => !!x[1],\n );\n try {\n logger.info(`Updating \"${existingPromptPartials.length}\" prompt partials...`);\n await updatePromptPartials(client, { input: existingPromptPartials, logger });\n logger.info(`Successfully updated \"${existingPromptPartials.length}\" prompt partials!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create prompt partials! - ${(err as Error).message}`);\n }\n\n logger.info(`Synced \"${promptPartials.length}\" prompt partials!`);\n\n return !encounteredError;\n}\n","import { map, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllPrompts } from './fetchPrompts.js';\nimport { UPDATE_PROMPTS, CREATE_PROMPT } from './gqls/prompt.js';\n\nexport interface PromptInput {\n /** Title of prompt */\n title: string;\n /** Prompt content */\n content: string;\n /** Status */\n status?: string;\n /** Temperature */\n temperature?: number;\n /** Top P */\n topP?: number;\n /** Max tokens to sample */\n maxTokensToSample?: number;\n}\n\n/**\n * Create a new prompt\n *\n * @param client - GraphQL client\n * @param input - Prompt input\n * @param options - Options\n * @returns Prompt ID\n */\nexport async function createPrompt(\n client: GraphQLClient,\n options: {\n /** Prompt to create */\n input: {\n /** Title of prompt */\n title: string;\n /** Prompt content */\n content: string;\n };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<string> {\n const { input, logger = NOOP_LOGGER } = options;\n const {\n createPrompt: { prompt },\n } = await makeGraphQLRequest<{\n /** createPrompt mutation */\n createPrompt: {\n /** Prompt */\n prompt: {\n /** ID */\n id: string;\n };\n };\n }>(client, CREATE_PROMPT, {\n // TODO: https://transcend.height.app/T-31994 - include models and groups, teams, users\n variables: { input },\n logger,\n });\n logger.info(`Successfully created prompt \"${input.title}\"!`);\n return prompt.id;\n}\n\n/**\n * Update a set of existing prompts\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updatePrompts(\n client: GraphQLClient,\n options: {\n /** [PromptInput, promptId] list */\n input: [PromptInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: prompts, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_PROMPTS, {\n variables: {\n input: {\n prompts: prompts.map(([prompt, id]) => ({\n ...prompt,\n id,\n })),\n },\n },\n logger,\n });\n logger.info(`Successfully updated ${prompts.length} prompts!`);\n}\n\n/**\n * Sync the prompts\n *\n * @param client - GraphQL client\n * @param prompts - Prompts\n * @param options - Options\n * @returns True if synced successfully\n */\nexport async function syncPrompts(\n client: GraphQLClient,\n prompts: PromptInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Concurrency */\n concurrency?: number;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER, concurrency = 20 } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${prompts.length}\" prompts...`);\n\n // Index existing prompts\n const existing = await fetchAllPrompts(client, { logger });\n const promptByTitle = keyBy(existing, 'title');\n\n // Determine which prompts are new vs existing\n const mapPromptsToExisting = prompts.map((promptInput) => [\n promptInput,\n promptByTitle[promptInput.title]?.id,\n ]);\n\n // Create the new prompts\n const newPrompts = mapPromptsToExisting\n .filter(([, existing]) => !existing)\n .map(([promptInput]) => promptInput as PromptInput);\n try {\n logger.info(`Creating \"${newPrompts.length}\" new prompts...`);\n await map(\n newPrompts,\n async (prompt) => {\n await createPrompt(client, { input: prompt, logger });\n },\n {\n concurrency,\n },\n );\n logger.info(`Successfully synced ${newPrompts.length} prompts!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create prompts! - ${(err as Error).message}`);\n }\n\n // Update existing prompts\n const existingPrompts = mapPromptsToExisting.filter((x): x is [PromptInput, string] => !!x[1]);\n try {\n logger.info(`Updating \"${existingPrompts.length}\" prompts...`);\n await updatePrompts(client, { input: existingPrompts, logger });\n logger.info(`Successfully updated \"${existingPrompts.length}\" prompts!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create prompts! - ${(err as Error).message}`);\n }\n\n logger.info(`Synced \"${prompts.length}\" prompts!`);\n\n return !encounteredError;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\n// orderBy: [\n// { field: createdAt, direction: ASC }\n// { field: title, direction: ASC }\n// ]\nexport const GLOBAL_ACTION_ITEM_COLLECTIONS = gql`\n query TranscendCliGlobalActionItemCollectionss(\n $filterBy: GlobalActionItemCollectionFiltersInput!\n ) {\n globalActionItemCollections(filterBy: $filterBy) {\n nodes {\n id\n title\n description\n hidden\n productLine\n }\n }\n }\n`;\n\nexport const CREATE_ACTION_ITEM_COLLECTION = gql`\n mutation TranscendCliCreateActionItemCollection($input: CreateActionItemCollectionInput!) {\n createActionItemCollection(input: $input) {\n created {\n id\n title\n }\n }\n }\n`;\n\nexport const UPDATE_ACTION_ITEM_COLLECTION = gql`\n mutation TranscendCliUpdateActionItemCollection($input: UpdateActionItemCollectionInput!) {\n updateActionItemCollection(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { TranscendProduct } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { GLOBAL_ACTION_ITEM_COLLECTIONS } from './gqls/actionItemCollection.js';\n\nexport interface ActionItemCollection {\n /** ID of collection */\n id: string;\n /** Title of collection */\n title: string;\n /** Description of collection */\n description: string;\n /** Whether section is hidden */\n hidden: boolean;\n /** Which locations/products the action item shows up in */\n productLine: TranscendProduct;\n}\n\n/**\n * Fetch all action item collections in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All action item collections in the organization\n */\nexport async function fetchAllActionItemCollections(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter by */\n filterBy?: {\n /** Filter on location */\n location?: TranscendProduct;\n };\n } = {},\n): Promise<ActionItemCollection[]> {\n const { logger, filterBy = {} } = options;\n const {\n globalActionItemCollections: { nodes },\n } = await makeGraphQLRequest<{\n /** ActionItemCollections */\n globalActionItemCollections: {\n /** List */\n nodes: ActionItemCollection[];\n };\n }>(client, GLOBAL_ACTION_ITEM_COLLECTIONS, {\n variables: {\n filterBy: {\n ...filterBy,\n },\n },\n logger,\n });\n return nodes;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\n// orderBy: [\n// { field: createdAt, direction: ASC }\n// { field: title, direction: ASC }\n// ]\nexport const GLOBAL_ACTION_ITEMS = gql`\n query TranscendCliGlobalActionItems(\n $first: Int!\n $offset: Int!\n $filterBy: GlobalActionItemFiltersInput!\n ) {\n globalActionItems(first: $first, offset: $offset, filterBy: $filterBy) {\n nodes {\n ids\n count\n teams {\n id\n name\n }\n customerExperienceActionItemIds\n users {\n id\n email\n }\n collections {\n title\n id\n }\n dueDate\n priority\n titles\n resolved\n notes\n links\n type\n additionalContexts {\n iconOverride\n requestId\n dataSiloId\n requestType\n latestAirgapVersion\n parentTitle\n }\n attributeValues {\n name\n attributeKey {\n name\n }\n }\n }\n }\n }\n`;\n\nexport const UPDATE_ACTION_ITEMS = gql`\n mutation TranscendCliUpdateActionItems($input: UpdateActionItemsInput!) {\n updateActionItems(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const CREATE_ACTION_ITEMS = gql`\n mutation TranscendCliCreateActionItems($input: [CreateActionItemsInput!]!) {\n createActionItems(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { ActionItemCode, ActionItemPriorityOverride } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { GLOBAL_ACTION_ITEMS } from './gqls/actionItem.js';\n\nexport interface ActionItemRaw {\n /** ID of action item */\n ids: string[];\n /** Count of action items */\n count: number;\n /** Teams assigned to action items */\n teams: {\n /** ID of team */\n id: string;\n /** Name of team */\n name: string;\n }[];\n /** Customer experience action item ID */\n customerExperienceActionItemIds: string[];\n /** Users assigned to the action item */\n users: {\n /** ID of user */\n id: string;\n /** User email */\n email: string;\n }[];\n /** Due date of action item */\n dueDate?: string;\n /** Priority of action item */\n priority?: ActionItemPriorityOverride;\n /** Titles of action items */\n titles: string[];\n /** Description of the action item */\n resolved: boolean;\n /** Notes */\n notes: string[];\n /** links */\n links: string[];\n /** Action item types */\n type: ActionItemCode;\n /** Custom fields */\n attributeValues: {\n /** Name of attribute value */\n name: string;\n /** Attribute key that the value represents */\n attributeKey: {\n /** Name of attribute team */\n name: string;\n };\n }[];\n /** Additional context related to action item */\n additionalContexts?: {\n /** Override of icon */\n iconOverride?: string;\n /** Request ID */\n requestId?: string;\n /** Data Silo ID */\n dataSiloId?: string;\n /** Request type */\n requestType?: string;\n /** Airgap version */\n latestAirgapVersion?: string;\n /** Parent title */\n parentTitle?: string;\n };\n /** Sections where action item is grouped under */\n collections: {\n /** ID of collection that action item belongs to */\n id: string;\n /** Title of collection */\n title: string;\n }[];\n}\n\nexport interface ActionItem extends Omit<ActionItemRaw, 'ids' | 'titles' | 'links' | 'notes'> {\n /** ID of action item */\n id: string;\n /** Title of action item */\n title: string;\n /** Notes */\n notes: string;\n /** Links */\n link: string;\n /** Sections where action item is grouped under */\n collections: {\n /** ID of collection that action item belongs to */\n id: string;\n /** Title of collection */\n title: string;\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all action items in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All action items in the organization\n */\nexport async function fetchAllActionItems(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter by */\n filterBy?: {\n /** Names of the action items to filter for */\n priority?: ActionItemPriorityOverride[];\n /** Type of action item */\n type?: ActionItemCode[];\n /** Whether resolved or not */\n resolved?: boolean;\n /** Filter for action items due before this date */\n startDueDate?: Date;\n /** Filter for action items due after this date */\n endDueDate?: Date;\n };\n } = {},\n): Promise<ActionItem[]> {\n const { logger, filterBy = {} } = options;\n const actionItems: ActionItem[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n globalActionItems: { nodes },\n } = await makeGraphQLRequest<{\n /** ActionItems */\n globalActionItems: {\n /** List */\n nodes: ActionItemRaw[];\n };\n }>(client, GLOBAL_ACTION_ITEMS, {\n variables: {\n first: PAGE_SIZE,\n offset,\n filterBy: {\n ...filterBy,\n ...(filterBy.startDueDate ? { startDueDate: filterBy.startDueDate.toISOString() } : {}),\n ...(filterBy.endDueDate ? { endDueDate: filterBy.endDueDate.toISOString() } : {}),\n },\n },\n logger,\n });\n actionItems.push(\n ...nodes.map((node) => ({\n ...node,\n id: node.ids[0]!,\n title: node.titles[0]!,\n notes: node.notes[0]!,\n link: node.links[0]!,\n })),\n );\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return actionItems;\n}\n","import { gql } from 'graphql-request';\n\nexport const ASSESSMENT_SECTION_FIELDS = `\n id\n title\n status\n index\n questions {\n id\n title\n index\n type\n subType\n placeholder\n description\n isRequired\n displayLogic\n riskLogic\n requireRiskEvaluation\n requireRiskMatrixEvaluation\n riskCategories {\n id\n title\n }\n riskFramework {\n id\n title\n description\n riskLevels {\n id\n title\n }\n riskCategories {\n id\n title\n }\n riskMatrixColumns {\n id\n title\n }\n riskMatrixRows {\n id\n title\n }\n riskMatrix {\n id\n title\n }\n creator {\n id\n email\n name\n }\n riskMatrixRowTitle\n riskMatrixColumnTitle\n }\n riskLevel {\n id\n title\n }\n reviewerRiskLevel {\n id\n title\n }\n riskLevelFromRiskMatrix {\n id\n title\n }\n answerOptions {\n id\n index\n value\n }\n selectedAnswers {\n ... on AssessmentAnswerInterface {\n id\n index\n value\n }\n }\n respondent {\n id\n email\n name\n }\n attributeKey {\n name\n }\n externalRespondentEmail\n comments {\n id\n content\n createdAt\n updatedAt\n author {\n id\n email\n name\n }\n }\n allowedMimeTypes\n updatedAt\n referenceId\n previousSubmissions {\n id\n updatedAt\n assessmentQuestionId\n answers {\n ... on AssessmentAnswerInterface {\n id\n index\n value\n }\n }\n }\n allowSelectOther\n syncModel\n syncColumn\n syncRowIds\n syncOverride\n }\n assignees {\n id\n email\n name\n }\n externalAssignees {\n id\n email\n }\n isReviewed\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\n// orderBy: [\n// { field: createdAt, direction: ASC }\n// { field: name, direction: ASC }\n// ]\nexport const ASSESSMENTS = gql`\n query TranscendCliAssessments(\n $first: Int!\n $offset: Int!\n $filterBy: AssessmentFormFiltersInput\n ) {\n assessmentForms(first: $first, offset: $offset, filterBy: $filterBy) {\n nodes {\n id\n creator {\n id\n email\n name\n }\n lastEditor {\n id\n email\n name\n }\n title\n description\n status\n assignees {\n id\n email\n name\n }\n externalAssignees {\n id\n email\n }\n reviewers {\n id\n email\n name\n }\n isLocked\n isArchived\n isExternallyCreated\n dueDate\n createdAt\n updatedAt\n assignedAt\n submittedAt\n approvedAt\n rejectedAt\n titleIsInternal\n retentionSchedule {\n id\n type\n durationDays\n operation\n }\n attributeValues {\n name\n attributeKey {\n name\n }\n }\n sections {\n ${ASSESSMENT_SECTION_FIELDS}\n }\n assessmentGroup {\n id\n title\n description\n }\n resources {\n resourceType\n ... on AttributeBusinessEntityResource {\n id\n title\n }\n ... on AttributeDataSiloResource {\n id\n title\n }\n ... on AttributeDataSubCategoryResource {\n id\n name\n category\n }\n ... on AttributeSubDataPointResource {\n id\n name\n }\n ... on AttributeProcessingPurposeSubCategoryResource {\n id\n name\n purpose\n }\n ... on AttributeRequestResource {\n id\n type\n }\n ... on AttributeVendorResource {\n id\n title\n }\n ... on AttributePromptResource {\n id\n title\n }\n ... on AttributePromptRunResource {\n id\n title\n }\n ... on AttributePromptGroupResource {\n id\n title\n }\n }\n syncedRows {\n resourceType\n ... on AttributeBusinessEntityResource {\n id\n title\n }\n ... on AttributeDataSiloResource {\n id\n title\n }\n ... on AttributeDataSubCategoryResource {\n id\n name\n category\n }\n ... on AttributeSubDataPointResource {\n id\n name\n }\n ... on AttributeProcessingPurposeSubCategoryResource {\n id\n name\n purpose\n }\n ... on AttributeVendorResource {\n id\n title\n }\n }\n }\n }\n }\n`;\n\nexport const IMPORT_ONE_TRUST_ASSESSMENT_FORMS = gql`\n mutation TranscendCliImportOneTrustAssessmentForms($input: ImportOnetrustAssessmentsInput!) {\n importOneTrustAssessmentForms(input: $input) {\n assessmentForms {\n id\n title\n }\n }\n }\n`;\n","import {\n AssessmentFormStatus,\n AssessmentQuestionSubType,\n AssessmentQuestionType,\n AssessmentSyncColumn,\n AssessmentSyncModel,\n AttributeSupportedResourceType,\n DataCategoryType,\n ProcessingPurpose,\n RetentionScheduleOperation,\n RetentionScheduleType,\n} from '@transcend-io/privacy-types';\n/* eslint-disable max-lines */\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { ASSESSMENTS } from './gqls/assessment.js';\n\n/**\n * Represents an assessment with various properties and metadata.\n */\nexport interface Assessment {\n /** The ID of the assessment */\n id: string;\n /** The user who created the assessment */\n creator: UserPreview;\n /** The user who last edited the assessment */\n lastEditor: UserPreview;\n /** The title of the assessment */\n title: string;\n /** The description of the assessment */\n description: string;\n /** The current status of the assessment */\n status: AssessmentFormStatus;\n /** The users assigned to the assessment */\n assignees: UserPreview[];\n /** The external users assigned to the assessment */\n externalAssignees: ExternalUser[];\n /** The users who are reviewers of the assessment */\n reviewers: UserPreview[];\n /** Indicates if the assessment is locked */\n isLocked: boolean;\n /** Indicates if the assessment is archived */\n isArchived: boolean;\n /** Indicates if the assessment was created externally */\n isExternallyCreated: boolean;\n /** The due date of the assessment */\n dueDate: string;\n /** The date when the assessment was created */\n createdAt: string;\n /** The date when the assessment was last updated */\n updatedAt: string;\n /** The date when the assessment was assigned */\n assignedAt: string;\n /** The date when the assessment was submitted */\n submittedAt: string;\n /** The date when the assessment was approved */\n approvedAt: string;\n /** The date when the assessment was rejected */\n rejectedAt: string;\n /** Indicates if the title of the assessment is internal */\n titleIsInternal: boolean;\n /** The retention schedule of the assessment */\n retentionSchedule?: RetentionSchedule;\n /** The attribute values associated with the assessment */\n attributeValues: AttributeValue[];\n /** The sections of the assessment */\n sections: AssessmentSection[];\n /** The group to which the assessment belongs */\n assessmentGroup: AssessmentGroup;\n /** The resources associated with the assessment */\n resources: AssessmentResource[];\n /** The rows that are synced with the assessment */\n syncedRows: AssessmentResource[];\n}\n\nexport interface UserPreview {\n /** ID of user */\n id: string;\n /** Email of user */\n email: string;\n /** Name of user */\n name: string;\n}\n\nexport interface ExternalUser {\n /** ID of external user */\n id: string;\n /** Email of external user */\n email: string;\n}\n\nexport interface RetentionSchedule {\n /** ID of retention schedule */\n id: string;\n /** Type */\n type: RetentionScheduleType;\n /** Duration of retention schedule */\n durationDays: number;\n /** The operation to perform on the retention schedule */\n operation: RetentionScheduleOperation;\n}\n\ninterface AttributeValue {\n /** Name of attribute value */\n name: string;\n /** Key */\n attributeKey: {\n /** Name of key */\n name: string;\n };\n}\n\nexport interface AssessmentSection {\n /** ID of section */\n id: string;\n /** Title of section */\n title: string;\n /** Status of section */\n status: string;\n /** Index of section */\n index: number;\n /** Questions */\n questions: AssessmentQuestion[];\n /** Assignees */\n assignees: UserPreview[];\n /** External assignees */\n externalAssignees: ExternalUser[];\n /** Whether is reviewed */\n isReviewed: boolean;\n}\n\n/**\n * Represents a question in the assessment.\n */\nexport interface AssessmentQuestion {\n /**\n * Unique identifier for the question.\n */\n id: string;\n /** Title of the question */\n title: string;\n /** Index of the question in the assessment */\n index: number;\n /** Type of the question */\n type: AssessmentQuestionType;\n /** Subtype of the question */\n subType: AssessmentQuestionSubType;\n /** Placeholder text for the question */\n placeholder: string;\n /** Description of the question */\n description: string;\n /** Indicates if the question is required */\n isRequired: boolean;\n /** Logic for displaying the question */\n displayLogic: string;\n /** Logic for assessing risk related to the question */\n riskLogic: string[];\n /** Indicates if risk evaluation is required for the question */\n requireRiskEvaluation: boolean;\n /** Indicates if risk matrix evaluation is required for the question */\n requireRiskMatrixEvaluation: boolean;\n /** Categories of risk associated with the question */\n riskCategories: RiskCategory[];\n /** Framework used for risk assessment */\n riskFramework?: RiskFramework;\n /** Level of risk associated with the question */\n riskLevel?: RiskLevel;\n /** Risk level assigned by the reviewer */\n reviewerRiskLevel?: RiskLevel;\n /** Risk level derived from the risk matrix */\n riskLevelFromRiskMatrix?: RiskLevel;\n /** Options available for answering the question */\n answerOptions: AssessmentAnswerOption[];\n /** Answers selected for the question */\n selectedAnswers: AssessmentAnswer[];\n /** User who responded to the question */\n respondent: UserPreview;\n /** Key attribute associated with the question */\n attributeKey?: {\n /** Name of key */\n name: string;\n };\n /** Email of the external respondent */\n externalRespondentEmail?: string;\n /** Comments related to the question */\n comments: unknown[];\n /** Allowed MIME types for file uploads in the question */\n allowedMimeTypes: string[];\n /** Timestamp of the last update to the question */\n updatedAt: string;\n /** Reference identifier for the question */\n referenceId: string;\n /** Previous submissions related to the question */\n previousSubmissions: AssessmentPreviousSubmission[];\n /** Indicates if selecting \"Other\" is allowed for the question */\n allowSelectOther: boolean;\n /** Model used for synchronization */\n syncModel: AssessmentSyncModel;\n /** Column used for synchronization */\n syncColumn: AssessmentSyncColumn;\n /** Row IDs used for synchronization */\n syncRowIds: string[];\n /** Indicates if synchronization override is allowed */\n syncOverride: boolean;\n}\n\nexport interface RiskCategory {\n /** ID of category */\n id: string;\n /** Title of category */\n title: string;\n}\n\nexport interface RiskFramework {\n /** ID of framework */\n id: string;\n /** Title of framework */\n title: string;\n /** Description of framework */\n description: string;\n /** Risk levels */\n riskLevels: RiskLevel[];\n /** Risk categories */\n riskCategories: RiskCategory[];\n /** Risk matrix columns */\n riskMatrixColumns: RiskMatrixColumn[];\n /** Risk matrix rows */\n riskMatrixRows: RiskMatrixRow[];\n /** Risk matrix settings */\n riskMatrix: RiskMatrix[][];\n /** Creator of risk framework */\n creator?: UserPreview;\n /** Risk matrix row title */\n riskMatrixRowTitle: string;\n /** Risk matrix column title */\n riskMatrixColumnTitle: string;\n}\n\nexport interface RiskLevel {\n /** ID of risk level */\n id: string;\n /** Title of risk level */\n title: string;\n}\n\nexport interface RiskMatrix {\n /** ID of risk matrix */\n id: string;\n /** Title of risk matrix */\n title: string;\n}\n\nexport interface RiskMatrixColumn {\n /** ID of column */\n id: string;\n /** Title of column */\n title: string;\n}\n\nexport interface RiskMatrixRow {\n /** ID of row */\n id: string;\n /** Title of row */\n title: string;\n}\n\nexport interface AssessmentAnswerOption {\n /** ID of answer option */\n id: string;\n /** Index of answer option */\n index: number;\n /** Value of answer */\n value: string;\n}\n\nexport interface AssessmentAnswer {\n /** ID of answer */\n id: string;\n /** Index of answer */\n index: number;\n /** Value of answer */\n value: string;\n}\n\nexport interface AssessmentComment {\n /** ID of comment */\n id: string;\n /** Content of comment */\n content: string;\n /** Date comment made */\n createdAt: string;\n /** Date comment updated */\n updatedAt: string;\n /** Author of comment */\n author?: UserPreview;\n}\n\nexport interface AssessmentPreviousSubmission {\n /** Id of submission */\n id: string;\n /** Date updated */\n updatedAt: string;\n /** ID of question */\n assessmentQuestionId: string;\n /** Answers */\n answers: AssessmentAnswer[];\n}\n\nexport interface AssessmentGroup {\n /** ID of group */\n id: string;\n /** Title of group */\n title: string;\n /** Description of group */\n description: string;\n}\n\nexport interface AssessmentResource {\n /** Type of resource */\n resourceType: AttributeSupportedResourceType;\n /** ID of resource */\n id: string;\n /** Title of resource */\n title?: string;\n /** Name of resource */\n name?: string;\n /** Category of resource */\n category?: DataCategoryType;\n /** Purpose of resource */\n purpose?: ProcessingPurpose;\n /** Type of integration */\n type?: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all assessments in the organization\n *\n * @param client - GraphQL client\n * @returns All assessments in the organization\n */\nexport async function fetchAllAssessments(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Assessment[]> {\n const { logger } = options;\n const assessments: Assessment[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n assessmentForms: { nodes },\n } = await makeGraphQLRequest<{\n /** Forms */\n assessmentForms: {\n /** Nodes */\n nodes: Assessment[];\n };\n }>(client, ASSESSMENTS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n assessments.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return assessments.sort((a, b) => a.title.localeCompare(b.title));\n}\n/* eslint-enable max-lines */\n","import {\n AssessmentsDisplayLogicAction,\n ComparisonOperator,\n LogicOperator,\n} from '@transcend-io/privacy-types';\nimport { decodeCodec, valuesOf } from '@transcend-io/type-utils';\nimport * as t from 'io-ts';\n\n// This codec is for rules that logically require a list of values to compare against.\nexport const AssessmentRuleWithOperands = t.type({\n dependsOnQuestionReferenceId: t.string,\n comparisonOperator: t.union([\n t.literal(ComparisonOperator.IsEqualTo),\n t.literal(ComparisonOperator.IsNotEqualTo),\n t.literal(ComparisonOperator.IsOneOf),\n t.literal(ComparisonOperator.IsNotOneOf),\n t.literal(ComparisonOperator.Contains),\n ]),\n comparisonOperands: t.array(t.string),\n});\n\n// This codec is for the specific rule that does NOT require comparison operands.\nexport const AssessmentRuleWithoutOperands = t.type({\n dependsOnQuestionReferenceId: t.string,\n comparisonOperator: t.union([\n t.literal(ComparisonOperator.IsNotShown),\n t.literal(ComparisonOperator.IsShown),\n ]),\n});\n\n/**\n * The final, flexible codec that accepts EITHER a rule with operands OR a rule without them.\n */\nexport const AssessmentRule = t.union([AssessmentRuleWithOperands, AssessmentRuleWithoutOperands]);\n/** Type override */\nexport type AssessmentRule = t.TypeOf<typeof AssessmentRule>;\n\nexport interface AssessmentNestedRule {\n /** The operator to use when comparing the nested rules */\n logicOperator: LogicOperator;\n /** The rules to evaluate and be compared with to other using the LogicOperator */\n rules?: AssessmentRule[];\n /** The nested rules to add one more level of nesting to the rules. They are also compared to each other. */\n nestedRules?: AssessmentNestedRule[];\n}\n\nexport const AssessmentNestedRule: t.RecursiveType<t.Type<AssessmentNestedRule>> = t.recursion(\n 'AssessmentNestedRule',\n (self) =>\n t.intersection([\n t.type({\n /** The operator to use when comparing the nested rules */\n logicOperator: valuesOf(LogicOperator),\n }),\n t.partial({\n /** The rules to evaluate and be compared with to other using the LogicOperator */\n rules: t.array(AssessmentRule),\n /** The nested rules to add one more level of nesting to the rules. They are also compared to each other. */\n nestedRules: t.array(self),\n }),\n ]),\n);\n\nexport const AssessmentAction = t.partial({\n action: valuesOf(AssessmentsDisplayLogicAction),\n rule: AssessmentRule,\n nestedRule: AssessmentNestedRule,\n});\n\n/** Type override */\nexport type AssessmentAction = t.TypeOf<typeof AssessmentAction>;\n\n/**\n * Parse the assessment display logic\n *\n * @param displayLogic - Stringified rule\n * @returns The parsed assessment display logic\n */\nexport function parseAssessmentDisplayLogic(displayLogic: string): AssessmentAction {\n return decodeCodec(AssessmentAction, displayLogic);\n}\n","import { ComparisonOperator } from '@transcend-io/privacy-types';\nimport { decodeCodec, valuesOf } from '@transcend-io/type-utils';\nimport * as t from 'io-ts';\n\nexport const AssessmentRiskLogic = t.intersection([\n t.partial({\n riskAssignment: t.partial({\n riskLevelId: t.string,\n riskMatrixRowId: t.string,\n riskMatrixColumnId: t.string,\n }),\n }),\n t.type({\n comparisonOperands: t.array(t.string),\n comparisonOperator: valuesOf(ComparisonOperator),\n }),\n]);\n\n/** Type override */\nexport type AssessmentRiskLogic = t.TypeOf<typeof AssessmentRiskLogic>;\n\n/**\n * Parse the assessment risk logic\n *\n * @param riskLogic - Stringified rule\n * @returns The parsed assessment risk logic\n */\nexport function parseAssessmentRiskLogic(riskLogic: string): AssessmentRiskLogic {\n return decodeCodec(AssessmentRiskLogic, riskLogic);\n}\n","import { TranscendProduct } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport {\n type ActionItemCollection,\n fetchAllActionItemCollections,\n} from './fetchAllActionItemCollections.js';\nimport {\n CREATE_ACTION_ITEM_COLLECTION,\n UPDATE_ACTION_ITEM_COLLECTION,\n} from './gqls/actionItemCollection.js';\n\nexport interface ActionItemCollectionInput {\n /** The display title of the collection */\n title: string;\n /** Locations where collection is shown */\n productLine: TranscendProduct;\n /** Description of collection */\n description?: string;\n /** Whether hidden */\n hidden?: boolean;\n}\n\n/**\n * Create a new action item collection\n *\n * @param client - GraphQL client\n * @param actionItemCollection - Input\n * @param options - Options\n * @returns Created action item collection\n */\nexport async function createActionItemCollection(\n client: GraphQLClient,\n options: {\n /** Action item collection to create */\n input: ActionItemCollectionInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<ActionItemCollection, 'id' | 'title'>> {\n const { input: actionItemCollection, logger = NOOP_LOGGER } = options;\n const input = {\n title: actionItemCollection.title,\n description: actionItemCollection.description || '',\n hidden: actionItemCollection.hidden || false,\n productLine: actionItemCollection.productLine,\n };\n\n const { createActionItemCollection } = await makeGraphQLRequest<{\n /** Create actionItemCollection mutation */\n createActionItemCollection: {\n /** Created actionItemCollection */\n created: ActionItemCollection;\n };\n }>(client, CREATE_ACTION_ITEM_COLLECTION, {\n variables: { input },\n logger,\n });\n return createActionItemCollection.created;\n}\n\n/**\n * Update an action item collection\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateActionItemCollection(\n client: GraphQLClient,\n options: {\n /** Action item collection input to update */\n input: ActionItemCollectionInput & {\n /** ID of action item collection to update */\n id: string;\n };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: actionItemCollection, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_ACTION_ITEM_COLLECTION, {\n variables: {\n input: {\n id: actionItemCollection.id,\n title: actionItemCollection.title,\n description: actionItemCollection.description,\n hidden: actionItemCollection.hidden,\n productLine: actionItemCollection.productLine,\n },\n },\n logger,\n });\n}\n\n/**\n * Sync the action item collections\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncActionItemCollections(\n client: GraphQLClient,\n inputs: ActionItemCollectionInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${inputs.length}\" action item collections...`);\n\n const existingActionItemCollections = await fetchAllActionItemCollections(client, { logger });\n\n const collectionByTitle: { [k in string]: ActionItemCollection } = keyBy(\n existingActionItemCollections,\n 'title',\n );\n\n const newCollections = inputs.filter((input) => !collectionByTitle[input.title]);\n\n await mapSeries(newCollections, async (input) => {\n try {\n await createActionItemCollection(client, { input, logger });\n logger.info(`Successfully created action item collection \"${input.title}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to create action item collection \"${input.title}\"! - ${(err as Error).message}`,\n );\n }\n });\n\n const actionItemsToUpdate = inputs\n .map((input) => [input, collectionByTitle[input.title]?.id])\n .filter((x): x is [ActionItemCollectionInput, string] => !!x[1]);\n await mapSeries(actionItemsToUpdate, async ([input, actionItemId]) => {\n try {\n await updateActionItemCollection(client, {\n input: { ...input, id: actionItemId },\n logger,\n });\n logger.info(`Successfully synced action item collection \"${input.title}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to sync action item collection \"${input.title}\"! - ${(err as Error).message}`,\n );\n }\n });\n\n return !encounteredError;\n}\n","import { ActionItemCode, ActionItemPriorityOverride } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { uniq, keyBy, chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport {\n type ActionItemCollection,\n fetchAllActionItemCollections,\n} from './fetchAllActionItemCollections.js';\nimport { fetchAllActionItems, type ActionItem } from './fetchAllActionItems.js';\nimport { UPDATE_ACTION_ITEMS, CREATE_ACTION_ITEMS } from './gqls/actionItem.js';\n\n/** Minimal attribute key shape needed for action item sync */\nexport interface ActionItemAttributeKey {\n /** ID of attribute */\n id: string;\n /** Name of attribute */\n name: string;\n}\n\nexport interface ActionItemInput {\n /** The display title of the action item */\n title: string;\n /** Action item type */\n type: ActionItemCode;\n /** The titles of the collections that the action item is grouped within */\n collections: string[];\n /** Priority of the action item */\n priority?: ActionItemPriorityOverride;\n /** Customer experience action item key */\n customerExperienceActionItemId?: string;\n /** Due date of the action item */\n dueDate?: string;\n /** Whether action item has been resolved */\n resolved?: boolean;\n /** Notes */\n notes?: string;\n /** Links to action items */\n link?: string;\n /** The email addresses of the employees assigned to the action item */\n users?: string[];\n /** The names of teams assigned to the action item */\n teams?: string[];\n /** Attribute value and its corresponding attribute key */\n attributes?: {\n /** Attribute key name */\n key: string;\n /** Attribute value names */\n values: string[];\n }[];\n}\n\n/**\n * Create new action items\n *\n * @param client - GraphQL client\n * @param actionItems - Action item inputs\n * @param actionItemCollectionByTitle - Action item collections indexed by title\n * @param options - Options\n */\nexport async function createActionItems(\n client: GraphQLClient,\n options: {\n /** Action items to create */\n input: ActionItemInput[];\n /** Logger instance */\n logger?: Logger;\n /** Action item collections indexed by title */\n actionItemCollectionByTitle: {\n [k in string]: ActionItemCollection;\n };\n // TODO: https://transcend.height.app/T-38961 - insert attributes\n /** Attribute keys indexed by name */\n attributeKeysByName?: {\n [k in string]: ActionItemAttributeKey;\n };\n },\n): Promise<void> {\n const { input: actionItems, logger = NOOP_LOGGER, actionItemCollectionByTitle } = options;\n // TODO: https://transcend.height.app/T-38961 - insert attributes\n // const getAttribute = (key: string): string => {\n // const existing = attributeKeysByName[key];\n // if (!existing) {\n // throw new Error(`Attribute key \"${key}\" does not exist!`);\n // }\n // return existing.id;\n // };\n const chunked = chunk(actionItems, 100);\n await mapSeries(chunked, async (chunkToUpload) => {\n await makeGraphQLRequest(client, CREATE_ACTION_ITEMS, {\n variables: {\n input: chunkToUpload.map((actionItem) => ({\n title: actionItem.title,\n type: actionItem.type,\n priorityOverride: actionItem.priority,\n dueDate: actionItem.dueDate,\n customerExperienceActionItemId: actionItem.customerExperienceActionItemId,\n resolved: actionItem.resolved,\n notes: actionItem.notes,\n link: actionItem.link,\n assigneesUserEmails: actionItem.users,\n assigneesTeamNames: actionItem.teams,\n ...(actionItem.attributes\n ? {\n // TODO: https://transcend.height.app/T-38961 - insert attributes\n // attributes: actionItem.attributes.map(({ key, values }) => ({\n // attributeKeyId: getAttribute(key),\n // attributeValueNames: values,\n // })),\n }\n : {}),\n collectionIds: actionItem.collections.map(\n (collectionTitle) => actionItemCollectionByTitle[collectionTitle]!.id,\n ),\n })),\n },\n logger,\n });\n });\n}\n\n/**\n * Update an action item\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateActionItem(\n client: GraphQLClient,\n options: {\n /** Action item input to update */\n input: ActionItemInput & {\n /** ID of action item to update */\n id: string;\n };\n /** Logger instance */\n logger?: Logger;\n /** Attribute keys indexed by name */\n attributeKeysByName?: {\n [k in string]: ActionItemAttributeKey;\n };\n },\n): Promise<void> {\n const { input: actionItem, logger = NOOP_LOGGER, attributeKeysByName = {} } = options;\n const getAttribute = (key: string): string => {\n const existing = attributeKeysByName[key];\n if (!existing) {\n throw new Error(`Attribute key \"${key}\" does not exist!`);\n }\n return existing.id;\n };\n await makeGraphQLRequest(client, UPDATE_ACTION_ITEMS, {\n variables: {\n input: {\n ids: [actionItem.id],\n title: actionItem.title,\n priorityOverride: actionItem.priority,\n dueDate: actionItem.dueDate,\n resolved: actionItem.resolved,\n customerExperienceActionItemId: actionItem.customerExperienceActionItemId,\n notes: actionItem.notes,\n link: actionItem.link,\n assigneesUserEmails: actionItem.users,\n assigneesTeamNames: actionItem.teams,\n ...(actionItem.attributes\n ? {\n attributes: actionItem.attributes.map(({ key, values }) => ({\n attributeKeyId: getAttribute(key),\n attributeValueNames: values,\n })),\n }\n : {}),\n },\n },\n logger,\n });\n}\n\n/**\n * Convert action item to a unique key\n *\n * @param actionItem - action item\n * @returns Unique key\n */\nfunction actionItemToUniqueCode({\n title,\n collections,\n}: Pick<ActionItem, 'title' | 'collections'>): string {\n return `${title}-${collections\n .map((c) => c.title)\n .sort()\n .join('-')}`;\n}\n\n/**\n * Convert action item input to a unique key\n *\n * @param actionItem - action item\n * @returns Unique key\n */\nfunction actionItemInputToUniqueCode({\n title,\n collections,\n}: Pick<ActionItemInput, 'title' | 'collections'>): string {\n return `${title}-${collections.sort().join('-')}`;\n}\n\n/**\n * Sync the action items\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncActionItems(\n client: GraphQLClient,\n inputs: ActionItemInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Pre-fetched attribute keys (pass result of fetchAllAttributes) */\n attributeKeys?: ActionItemAttributeKey[];\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER, attributeKeys = [] } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${inputs.length}\" actionItems...`);\n\n const [existingActionItems, existingActionItemCollections] = await Promise.all([\n fetchAllActionItems(client, { logger }),\n fetchAllActionItemCollections(client, { logger }),\n ]);\n\n const actionItemCollectionByTitle: { [k in string]: ActionItemCollection } = keyBy(\n existingActionItemCollections,\n 'title',\n );\n const actionItemByTitle = keyBy(existingActionItems, actionItemToUniqueCode) as {\n [k in string]: ActionItem;\n };\n const attributeKeysByName = keyBy(attributeKeys, 'name');\n const actionItemByCxId = keyBy(\n existingActionItems.filter((x) => !!x.customerExperienceActionItemIds),\n ({ customerExperienceActionItemIds }) => customerExperienceActionItemIds[0],\n ) as { [k in string]: ActionItem };\n\n const missingCollections = uniq(inputs.map((input) => input.collections).flat()).filter(\n (collectionTitle) => !actionItemCollectionByTitle[collectionTitle],\n );\n if (missingCollections.length > 0) {\n logger.error(\n `Missing action item collections: \"${missingCollections.join(\n '\", \"',\n )}\" - please create them first!`,\n );\n return false;\n }\n\n const newActionItems = inputs.filter(\n (input) =>\n !actionItemByTitle[actionItemInputToUniqueCode(input)] &&\n !actionItemByCxId[input.customerExperienceActionItemId!],\n );\n\n if (newActionItems.length > 0) {\n try {\n logger.info(`Creating \"${newActionItems.length}\" actionItems...`);\n await createActionItems(client, {\n input: newActionItems,\n logger,\n actionItemCollectionByTitle,\n attributeKeysByName,\n });\n logger.info(`Successfully created \"${newActionItems.length}\" actionItems!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create action items! - ${(err as Error).message}`);\n }\n }\n\n const actionItemsToUpdate = inputs\n .map((input) => [\n input,\n actionItemByTitle[actionItemInputToUniqueCode(input)]?.id ||\n actionItemByCxId[input.customerExperienceActionItemId!]?.id,\n ])\n .filter((x): x is [ActionItemInput, string] => !!x[1]);\n await mapSeries(actionItemsToUpdate, async ([input, actionItemId]) => {\n try {\n await updateActionItem(client, {\n input: { ...input, id: actionItemId },\n logger,\n attributeKeysByName,\n });\n logger.info(`Successfully synced action item \"${input.title}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync action item \"${input.title}\"! - ${(err as Error).message}`);\n }\n });\n\n return !encounteredError;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const CODE_PACKAGES = gql`\n query TranscendCliCodePackages($first: Int!, $offset: Int!, $input: CodePackageFiltersInput) {\n codePackages(\n first: $first\n offset: $offset\n filterBy: $input\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n description\n type\n relativePath\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n repository {\n id\n name\n }\n dataSilo {\n id\n title\n type\n }\n }\n }\n }\n`;\n\nexport const UPDATE_CODE_PACKAGES = gql`\n mutation TranscendCliUpdateCodePackages($input: UpdateCodePackagesInput!) {\n updateCodePackages(input: $input) {\n clientMutationId\n codePackages {\n id\n name\n description\n type\n relativePath\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n repository {\n id\n name\n }\n dataSilo {\n id\n title\n type\n }\n }\n }\n }\n`;\n\nexport const CREATE_CODE_PACKAGE = gql`\n mutation TranscendCliCreateCodePackage($input: CreateCodePackageInput!) {\n createCodePackage(input: $input) {\n clientMutationId\n codePackage {\n id\n name\n description\n type\n relativePath\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n repository {\n id\n name\n }\n dataSilo {\n id\n title\n type\n }\n }\n }\n }\n`;\n","import { CodePackageType } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { CODE_PACKAGES } from './gqls/codePackage.js';\n\nexport interface CodePackage {\n /** ID of code package */\n id: string;\n /** Name of code package */\n name: string;\n /** Description of code package */\n description: string;\n /** Type of code package */\n type: CodePackageType;\n /** Relative path to code package in repository */\n relativePath: string;\n /** The teams that manage the code package */\n teams: {\n /** ID of team */\n id: string;\n /** Name of team */\n name: string;\n }[];\n /** The users that manage the code package */\n owners: {\n /** ID of user */\n id: string;\n /** Email of user */\n email: string;\n }[];\n /** The repository where the code package belongs */\n repository: {\n /** ID of repository */\n id: string;\n /** Name of repository */\n name: string;\n };\n /** The data silo that the code package relates to */\n dataSilo?: {\n /** ID of repository */\n id: string;\n /** Title of repository */\n title: string;\n /** Type of data silo */\n type: string;\n };\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all code packages in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All code packages in the organization\n */\nexport async function fetchAllCodePackages(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<CodePackage[]> {\n const { logger } = options;\n const codePackages: CodePackage[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n codePackages: { nodes },\n } = await makeGraphQLRequest<{\n /** Code packages */\n codePackages: {\n /** List */\n nodes: CodePackage[];\n };\n }>(client, CODE_PACKAGES, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n codePackages.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return codePackages.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const REPOSITORIES = gql`\n query TranscendCliRepositories($first: Int!, $offset: Int!, $input: RepositoryFiltersInput) {\n repositories(\n first: $first\n offset: $offset\n filterBy: $input\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n description\n url\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n }\n }\n }\n`;\n\nexport const UPDATE_REPOSITORIES = gql`\n mutation TranscendCliUpdateRepositories($input: UpdateRepositoriesInput!) {\n updateRepositories(input: $input) {\n clientMutationId\n repositories {\n id\n name\n url\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n }\n }\n }\n`;\n\nexport const CREATE_REPOSITORY = gql`\n mutation TranscendCliCreateRepository($input: CreateRepositoryInput!) {\n createRepository(input: $input) {\n clientMutationId\n repository {\n id\n name\n url\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n }\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { REPOSITORIES } from './gqls/repository.js';\n\nexport interface Repository {\n /** ID of repository */\n id: string;\n /** Name of repository */\n name: string;\n /** Description of repository */\n description: string;\n /** URL of repo */\n url: string;\n /** The teams that manage the repository */\n teams: {\n /** ID of team */\n id: string;\n /** Name of team */\n name: string;\n }[];\n /** The users that manage the repository */\n owners: {\n /** ID of user */\n id: string;\n /** Email of user */\n email: string;\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all repositories in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All repositories in the organization\n */\nexport async function fetchAllRepositories(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Repository[]> {\n const { logger } = options;\n const repositories: Repository[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n repositories: { nodes },\n } = await makeGraphQLRequest<{\n /** Repositories */\n repositories: {\n /** List */\n nodes: Repository[];\n };\n }>(client, REPOSITORIES, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n repositories.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return repositories.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const SOFTWARE_DEVELOPMENT_KITS = gql`\n query TranscendCliSoftwareDevelopmentKits(\n $first: Int!\n $offset: Int!\n $input: SoftwareDevelopmentKitFiltersInput\n ) {\n softwareDevelopmentKits(\n first: $first\n offset: $offset\n filterBy: $input\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n description\n codePackageType\n documentationLinks\n repositoryUrl\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n }\n }\n }\n`;\n\nexport const UPDATE_SOFTWARE_DEVELOPMENT_KITS = gql`\n mutation TranscendCliUpdateSoftwareDevelopmentKits($input: UpdateSoftwareDevelopmentKitsInput!) {\n updateSoftwareDevelopmentKits(input: $input) {\n clientMutationId\n softwareDevelopmentKits {\n id\n name\n description\n codePackageType\n documentationLinks\n repositoryUrl\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n }\n }\n }\n`;\n\nexport const CREATE_SOFTWARE_DEVELOPMENT_KIT = gql`\n mutation TranscendCliCreateSoftwareDevelopmentKit($input: CreateSoftwareDevelopmentKitInput!) {\n createSoftwareDevelopmentKit(input: $input) {\n clientMutationId\n softwareDevelopmentKit {\n id\n name\n description\n codePackageType\n documentationLinks\n repositoryUrl\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n }\n }\n }\n`;\n","import { CodePackageType } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { SOFTWARE_DEVELOPMENT_KITS } from './gqls/softwareDevelopmentKit.js';\n\nexport interface SoftwareDevelopmentKit {\n /** ID of software development kit */\n id: string;\n /** Name of software development kit */\n name: string;\n /** Description of software development kit */\n description: string;\n /** Type of software development kit */\n codePackageType: CodePackageType;\n /** Related documentation */\n documentationLinks: string[];\n /** Link to git repository */\n repositoryUrl?: string;\n /** The teams that manage the software development kit */\n teams: {\n /** ID of team */\n id: string;\n /** Name of team */\n name: string;\n }[];\n /** The users that manage the software development kit */\n owners: {\n /** ID of user */\n id: string;\n /** Email of user */\n email: string;\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all software development kits in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All software development kits in the organization\n */\nexport async function fetchAllSoftwareDevelopmentKits(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<SoftwareDevelopmentKit[]> {\n const { logger } = options;\n const softwareDevelopmentKits: SoftwareDevelopmentKit[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n softwareDevelopmentKits: { nodes },\n } = await makeGraphQLRequest<{\n /** Software development kits */\n softwareDevelopmentKits: {\n /** List */\n nodes: SoftwareDevelopmentKit[];\n };\n }>(client, SOFTWARE_DEVELOPMENT_KITS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n softwareDevelopmentKits.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return softwareDevelopmentKits.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { mapSeries, map, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk, keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllRepositories, type Repository } from './fetchAllRepositories.js';\nimport { UPDATE_REPOSITORIES, CREATE_REPOSITORY } from './gqls/repository.js';\n\nexport interface RepositoryInput {\n /** Title of repository */\n name: string;\n /** Description of the repository */\n description?: string;\n /** Github repository URL */\n url: string;\n}\n\nconst CHUNK_SIZE = 100;\n\n/**\n * Create a new repository\n *\n * @param client - GraphQL client\n * @param input - Repository input\n * @param options - Options\n * @returns Created repository\n */\nexport async function createRepository(\n client: GraphQLClient,\n options: {\n /** Repository to create */\n input: {\n /** Title of repository */\n name: string;\n /** Description of the repository */\n description?: string;\n /** Github repository */\n url: string;\n /** User IDs of owners */\n ownerIds?: string[];\n /** Emails of owners */\n ownerEmails?: string[];\n /** Team IDs */\n teamIds?: string[];\n /** Team names */\n teamNames?: string[];\n };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Repository> {\n const { input, logger = NOOP_LOGGER } = options;\n const {\n createRepository: { repository },\n } = await makeGraphQLRequest<{\n /** createRepository mutation */\n createRepository: {\n /** Software development kit */\n repository: Repository;\n };\n }>(client, CREATE_REPOSITORY, {\n variables: { input },\n logger,\n });\n logger.info(`Successfully created repository \"${input.name}\"!`);\n return repository;\n}\n\n/**\n * Update an existing repository\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Updated repositories\n */\nexport async function updateRepositories(\n client: GraphQLClient,\n options: {\n /** Repository inputs to update */\n input: {\n /** ID of repository */\n id: string;\n /** Title of repository */\n name?: string;\n /** Description of the repository */\n description?: string;\n /** Github repository */\n url?: string;\n /** User IDs of owners */\n ownerIds?: string[];\n /** Emails of owners */\n ownerEmails?: string[];\n /** Team IDs */\n teamIds?: string[];\n /** Team names */\n teamNames?: string[];\n }[];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Repository[]> {\n const { input: repositories, logger = NOOP_LOGGER } = options;\n const {\n updateRepositories: { repositories: updatedRepositories },\n } = await makeGraphQLRequest<{\n /** updateRepositories mutation */\n updateRepositories: {\n /** Software development kit */\n repositories: Repository[];\n };\n }>(client, UPDATE_REPOSITORIES, {\n variables: {\n input: {\n repositories,\n },\n },\n logger,\n });\n logger.info(`Successfully updated ${repositories.length} repositories!`);\n return updatedRepositories;\n}\n\n/**\n * Sync the repositories\n *\n * @param client - GraphQL client\n * @param repositories - Repositories\n * @param options - Options\n * @returns The repositories that were upserted and whether the sync was successful\n */\nexport async function syncRepositories(\n client: GraphQLClient,\n repositories: RepositoryInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Concurrency */\n concurrency?: number;\n } = {},\n): Promise<{\n /** The repositories that were upserted */\n repositories: Repository[];\n /** If successful */\n success: boolean;\n}> {\n const { logger = NOOP_LOGGER, concurrency = 20 } = options;\n let encounteredError = false;\n const repos: Repository[] = [];\n\n // Index existing repositories\n const existing = await fetchAllRepositories(client, { logger });\n const repositoryByName = keyBy(existing, 'name');\n\n // Determine which repositories are new vs existing\n const mapRepositoriesToExisting = repositories.map((repoInput) => [\n repoInput,\n repositoryByName[repoInput.name]?.id,\n ]);\n\n // Create the new repositories\n const newRepositories = mapRepositoriesToExisting\n .filter(([, existing]) => !existing)\n .map(([repoInput]) => repoInput as RepositoryInput);\n try {\n logger.info(`Creating \"${newRepositories.length}\" new repositories...`);\n await map(\n newRepositories,\n async (repo) => {\n const newRepo = await createRepository(client, { input: repo, logger });\n repos.push(newRepo);\n },\n {\n concurrency,\n },\n );\n logger.info(`Successfully synced ${newRepositories.length} repositories!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create repositories! - ${(err as Error).message}`);\n }\n\n // Update existing repositories\n const existingRepositories = mapRepositoriesToExisting.filter(\n (x): x is [RepositoryInput, string] => !!x[1],\n );\n const chunks = chunk(existingRepositories, CHUNK_SIZE);\n logger.info(`Updating \"${existingRepositories.length}\" repositories...`);\n\n await mapSeries(chunks, async (chunk) => {\n try {\n const updatedRepos = await updateRepositories(client, {\n input: chunk.map(([input, id]) => ({\n ...input,\n id,\n })),\n logger,\n });\n repos.push(...updatedRepos);\n logger.info(`Successfully updated \"${existingRepositories.length}\" repositories!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to update repositories! - ${(err as Error).message}`);\n }\n\n logger.info(`Synced \"${repositories.length}\" repositories!`);\n });\n\n // Return true upon success\n return {\n repositories: repos,\n success: !encounteredError,\n };\n}\n","import { CodePackageType } from '@transcend-io/privacy-types';\nimport { mapSeries, map, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk, keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport {\n fetchAllSoftwareDevelopmentKits,\n type SoftwareDevelopmentKit,\n} from './fetchAllSoftwareDevelopmentKits.js';\nimport {\n UPDATE_SOFTWARE_DEVELOPMENT_KITS,\n CREATE_SOFTWARE_DEVELOPMENT_KIT,\n} from './gqls/softwareDevelopmentKit.js';\n\nexport interface SoftwareDevelopmentKitInput {\n /** Title of software development kit */\n name: string;\n /** Code package type */\n codePackageType: CodePackageType;\n /** Description of the SDK */\n description?: string;\n /** Github repository URL */\n repositoryUrl?: string;\n /** Integration name */\n catalogIntegrationName?: string;\n /** Documentation links */\n documentationLinks?: string[];\n}\n\nconst CHUNK_SIZE = 100;\n\n/**\n * Create a new software development kit\n *\n * @param client - GraphQL client\n * @param input - Software development kit input\n * @param options - Options\n * @returns Created software development kit\n */\nexport async function createSoftwareDevelopmentKit(\n client: GraphQLClient,\n options: {\n /** Software development kit to create */\n input: {\n /** Title of software development kit */\n name: string;\n /** Code package type */\n codePackageType: CodePackageType;\n /** Description of the SDK */\n description?: string;\n /** Github repository */\n repositoryUrl?: string;\n /** Integration name */\n catalogIntegrationName?: string;\n /** Doc links */\n documentationLinks?: string[];\n /** Code package IDs */\n codePackageIds?: string[];\n /** Code package names */\n codePackageNames?: string[];\n /** User IDs of owners */\n ownerIds?: string[];\n /** Emails of owners */\n ownerEmails?: string[];\n /** Team IDs */\n teamIds?: string[];\n /** Team names */\n teamNames?: string[];\n };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<SoftwareDevelopmentKit> {\n const { input, logger = NOOP_LOGGER } = options;\n const {\n createSoftwareDevelopmentKit: { softwareDevelopmentKit },\n } = await makeGraphQLRequest<{\n /** createSoftwareDevelopmentKit mutation */\n createSoftwareDevelopmentKit: {\n /** Software development kit */\n softwareDevelopmentKit: SoftwareDevelopmentKit;\n };\n }>(client, CREATE_SOFTWARE_DEVELOPMENT_KIT, {\n variables: { input },\n logger,\n });\n logger.info(`Successfully created software development kit \"${input.name}\"!`);\n return softwareDevelopmentKit;\n}\n\n/**\n * Update an existing software development kit\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Updated software development kits\n */\nexport async function updateSoftwareDevelopmentKits(\n client: GraphQLClient,\n options: {\n /** Software development kit inputs to update */\n input: {\n /** ID of software development kit */\n id: string;\n /** Title of software development kit */\n name?: string;\n /** Description of the SDK */\n description?: string;\n /** Github repository */\n repositoryUrl?: string;\n /** Integration name */\n catalogIntegrationName?: string;\n /** Doc links */\n documentationLinks?: string[];\n /** Code package IDs */\n codePackageIds?: string[];\n /** Code package names */\n codePackageNames?: string[];\n /** User IDs of owners */\n ownerIds?: string[];\n /** Emails of owners */\n ownerEmails?: string[];\n /** Team IDs */\n teamIds?: string[];\n /** Team names */\n teamNames?: string[];\n }[];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<SoftwareDevelopmentKit[]> {\n const { input: sdks, logger = NOOP_LOGGER } = options;\n const {\n updateSoftwareDevelopmentKits: { softwareDevelopmentKits },\n } = await makeGraphQLRequest<{\n /** updateSoftwareDevelopmentKits mutation */\n updateSoftwareDevelopmentKits: {\n /** Software development kit */\n softwareDevelopmentKits: SoftwareDevelopmentKit[];\n };\n }>(client, UPDATE_SOFTWARE_DEVELOPMENT_KITS, {\n variables: {\n input: {\n softwareDevelopmentKits: sdks,\n },\n },\n logger,\n });\n logger.info(`Successfully updated ${sdks.length} software development kits!`);\n return softwareDevelopmentKits;\n}\n\n/**\n * Sync the software development kits\n *\n * @param client - GraphQL client\n * @param softwareDevelopmentKits - Software development kits\n * @param options - Options\n * @returns The software development kits that were upserted and whether the sync was successful\n */\nexport async function syncSoftwareDevelopmentKits(\n client: GraphQLClient,\n softwareDevelopmentKits: SoftwareDevelopmentKitInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Concurrency */\n concurrency?: number;\n } = {},\n): Promise<{\n /** The SDKs that were upserted */\n softwareDevelopmentKits: SoftwareDevelopmentKit[];\n /** If successful */\n success: boolean;\n}> {\n const { logger = NOOP_LOGGER, concurrency = 20 } = options;\n let encounteredError = false;\n const sdks: SoftwareDevelopmentKit[] = [];\n logger.info('Syncing software development kits...');\n\n // Index existing software development kits\n const existing = await fetchAllSoftwareDevelopmentKits(client, { logger });\n const softwareDevelopmentKitByTitle = keyBy(existing, ({ name, codePackageType }) =>\n JSON.stringify({ name, codePackageType }),\n );\n\n // Determine which software development kits are new vs existing\n const mapSoftwareDevelopmentKitsToExisting = softwareDevelopmentKits.map((sdkInput) => [\n sdkInput,\n softwareDevelopmentKitByTitle[\n JSON.stringify({\n name: sdkInput.name,\n codePackageType: sdkInput.codePackageType,\n })\n ]?.id,\n ]);\n\n // Create the new software development kits\n const newSoftwareDevelopmentKits = mapSoftwareDevelopmentKitsToExisting\n .filter(([, existing]) => !existing)\n .map(([sdkInput]) => sdkInput as SoftwareDevelopmentKitInput);\n try {\n logger.info(`Creating \"${newSoftwareDevelopmentKits.length}\" new software development kits...`);\n await map(\n newSoftwareDevelopmentKits,\n async (sdk) => {\n const newSdk = await createSoftwareDevelopmentKit(client, { input: sdk, logger });\n sdks.push(newSdk);\n },\n {\n concurrency,\n },\n );\n logger.info(\n `Successfully synced ${newSoftwareDevelopmentKits.length} software development kits!`,\n );\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create software development kits! - ${(err as Error).message}`);\n }\n\n // Update existing software development kits\n const existingSoftwareDevelopmentKits = mapSoftwareDevelopmentKitsToExisting.filter(\n (x): x is [SoftwareDevelopmentKitInput, string] => !!x[1],\n );\n const chunks = chunk(existingSoftwareDevelopmentKits, CHUNK_SIZE);\n logger.info(`Updating \"${existingSoftwareDevelopmentKits.length}\" software development kits...`);\n\n await mapSeries(chunks, async (chunk) => {\n try {\n const updatedSdks = await updateSoftwareDevelopmentKits(client, {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n input: chunk.map(([{ codePackageType, ...input }, id]) => ({\n ...input,\n id,\n })),\n logger,\n });\n sdks.push(...updatedSdks);\n logger.info(\n `Successfully updated \"${existingSoftwareDevelopmentKits.length}\" software development kits!`,\n );\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to update software development kits! - ${(err as Error).message}`);\n }\n\n logger.info(`Synced \"${softwareDevelopmentKits.length}\" software development kits!`);\n });\n\n // Return true upon success\n return {\n softwareDevelopmentKits: sdks,\n success: !encounteredError,\n };\n}\n","import { describePackageName } from '@transcend-io/utils';\n\nexport interface MonorepoPackageDefinition {\n directory: string;\n displayName: string;\n packageName: string;\n}\n\nexport function createMonorepoPackageDefinition(\n name: string,\n directory: string,\n): MonorepoPackageDefinition {\n const packageNameParts = describePackageName(name);\n\n return {\n directory,\n displayName: packageNameParts.displayName,\n packageName: `@transcend-io/${packageNameParts.slug}`,\n };\n}\n\nexport * from './gqls/index.js';\nexport * from './api/index.js';\nexport * from './data-inventory/index.js';\nexport * from './preference-management/index.js';\nexport * from './administration/index.js';\nexport * from './consent/index.js';\nexport * from './dsr-automation/index.js';\nexport * from './ai/index.js';\nexport * from './assessments/index.js';\nexport * from './code-intelligence/index.js';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PURPOSES","PAGE_SIZE","PURPOSES","PAGE_SIZE","pmap","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","MAX_PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","MAX_PAGE_SIZE","MAX_PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","CHUNK_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","CHUNK_SIZE"],"sources":["../src/gqls/shared.ts","../src/api/buildTranscendGraphQLClient.ts","../src/api/makeGraphQLRequest.ts","../src/api/gqls/organization.ts","../src/api/createSombraGotInstance.ts","../src/data-inventory/gqls/businessEntity.ts","../src/data-inventory/fetchAllBusinessEntities.ts","../src/data-inventory/gqls/dataCategory.ts","../src/data-inventory/fetchAllDataCategories.ts","../src/data-inventory/gqls/dataPoint.ts","../src/data-inventory/fetchAllDataPoints.ts","../src/data-inventory/gqls/dataSilo.ts","../src/data-inventory/fetchAllDataSilos.ts","../src/data-inventory/gqls/identifier.ts","../src/data-inventory/fetchAllIdentifiers.ts","../src/data-inventory/gqls/processingActivity.ts","../src/data-inventory/fetchAllProcessingActivities.ts","../src/data-inventory/gqls/vendor.ts","../src/data-inventory/fetchAllVendors.ts","../src/data-inventory/fetchEnrichedDataSilos.ts","../src/data-inventory/syncBusinessEntities.ts","../src/data-inventory/syncDataCategories.ts","../src/data-inventory/syncDataSiloDependencies.ts","../src/data-inventory/syncProcessingActivities.ts","../src/data-inventory/syncVendors.ts","../src/preference-management/gqls/purpose.ts","../src/preference-management/fetchAllPurposes.ts","../src/preference-management/gqls/preferenceTopic.ts","../src/preference-management/fetchAllPreferenceTopics.ts","../src/preference-management/fetchAllPurposesAndPreferences.ts","../src/preference-management/gqls/preferenceAccessTokens.ts","../src/preference-management/createPreferenceAccessTokens.ts","../src/preference-management/types.ts","../src/preference-management/codecs.ts","../src/preference-management/getPreferenceMetadataFromRow.ts","../src/preference-management/getPreferenceIdentifiersFromRow.ts","../src/preference-management/getUniquePreferenceIdentifierNamesFromRow.ts","../src/preference-management/getPreferenceUpdatesFromRow.ts","../src/preference-management/checkIfPendingPreferenceUpdatesAreNoOp.ts","../src/preference-management/checkIfPendingPreferenceUpdatesCauseConflict.ts","../src/preference-management/withPreferenceRetry.ts","../src/preference-management/transformPreferenceRecordToCsv.ts","../src/preference-management/buildConsentChunks.ts","../src/preference-management/pickConsentChunkMode.ts","../src/preference-management/getComparisonTimeForRecord.ts","../src/preference-management/iterateConsentPages.ts","../src/preference-management/consentWindowHasAny.ts","../src/preference-management/discoverConsentWindow.ts","../src/preference-management/fetchConsentPreferences.ts","../src/preference-management/getPreferencesForIdentifiers.ts","../src/preference-management/fetchConsentPreferencesChunked.ts","../src/preference-management/loadReferenceData.ts","../src/administration/gqls/attribute.ts","../src/administration/fetchAllAttributes.ts","../src/administration/gqls/message.ts","../src/administration/fetchAllMessages.ts","../src/administration/gqls/team.ts","../src/administration/fetchAllTeams.ts","../src/administration/gqls/user.ts","../src/administration/fetchAllUsers.ts","../src/administration/gqls/apiKey.ts","../src/administration/fetchApiKeys.ts","../src/administration/formatRegions.ts","../src/administration/gqls/auth.ts","../src/administration/loginUser.ts","../src/administration/manageApiKeys.ts","../src/administration/setResourceAttributes.ts","../src/administration/syncAttribute.ts","../src/administration/syncIntlMessages.ts","../src/administration/syncTeams.ts","../src/administration/gqls/attributeKey.ts","../src/consent/createTranscendConsentGotInstance.ts","../src/consent/gqls/consentManager.ts","../src/consent/deployConsentManager.ts","../src/consent/gqls/consentManagerMetrics.ts","../src/consent/gqls/experiences.ts","../src/consent/fetchConsentManagerId.ts","../src/consent/gqls/shared.ts","../src/consent/gqls/cookies.ts","../src/consent/fetchAllCookies.ts","../src/consent/gqls/dataFlows.ts","../src/consent/fetchAllDataFlows.ts","../src/consent/gqls/privacyCenter.ts","../src/consent/fetchPrivacyCenterId.ts","../src/consent/gqls/policy.ts","../src/consent/fetchAllPolicies.ts","../src/consent/fetchAllPrivacyCenters.ts","../src/consent/gqls/processingPurpose.ts","../src/consent/fetchAllProcessingPurposes.ts","../src/consent/gqls/purposes.ts","../src/consent/gqls/partitions.ts","../src/consent/gqls/stats.ts","../src/consent/syncPartitions.ts","../src/consent/syncConsentManager.ts","../src/consent/syncCookies.ts","../src/consent/syncDataFlows.ts","../src/consent/syncPolicies.ts","../src/consent/syncPrivacyCenter.ts","../src/consent/syncProcessingPurposes.ts","../src/dsr-automation/gqls/requestEnricher.ts","../src/dsr-automation/fetchAllRequestEnrichers.ts","../src/dsr-automation/gqls/sombraVersion.ts","../src/dsr-automation/fetchAllRequestIdentifiers.ts","../src/dsr-automation/gqls/requestIdentifier.ts","../src/dsr-automation/fetchAllRequestIdentifierMetadata.ts","../src/dsr-automation/gqls/dataSubject.ts","../src/dsr-automation/fetchDataSubjects.ts","../src/dsr-automation/gqls/dsrIdentifier.ts","../src/dsr-automation/fetchIdentifiers.ts","../src/dsr-automation/retryRequestEnricher.ts","../src/dsr-automation/syncDataSubject.ts","../src/dsr-automation/gqls/enricher.ts","../src/dsr-automation/syncEnrichers.ts","../src/dsr-automation/syncIdentifier.ts","../src/dsr-automation/gqls/siloDiscovery.ts","../src/dsr-automation/fetchActiveSiloDiscoPlugin.ts","../src/dsr-automation/gqls/action.ts","../src/dsr-automation/fetchAllActions.ts","../src/dsr-automation/fetchAllAttributeKeys.ts","../src/dsr-automation/gqls/siloDiscoveryResult.ts","../src/dsr-automation/fetchAllSiloDiscoveryResults.ts","../src/dsr-automation/gqls/catalog.ts","../src/dsr-automation/fetchCatalogs.ts","../src/dsr-automation/gqls/requestDataSilo.ts","../src/dsr-automation/fetchRequestDataSilo.ts","../src/dsr-automation/gqls/requestFile.ts","../src/dsr-automation/fetchRequestFilesForRequest.ts","../src/dsr-automation/formatAttributeValues.ts","../src/dsr-automation/syncAction.ts","../src/dsr-automation/gqls/template.ts","../src/dsr-automation/syncTemplates.ts","../src/dsr-automation/uploadSiloDiscoveryResults.ts","../src/ai/gqls/promptRun.ts","../src/ai/addMessagesToPromptRun.ts","../src/ai/gqls/agentFile.ts","../src/ai/fetchAllAgentFiles.ts","../src/ai/gqls/agentFunction.ts","../src/ai/fetchAllAgentFunctions.ts","../src/ai/gqls/agent.ts","../src/ai/fetchAllAgents.ts","../src/ai/gqls/largeLanguageModel.ts","../src/ai/fetchLargeLanguageModels.ts","../src/ai/gqls/prompt.ts","../src/ai/fetchPromptGroups.ts","../src/ai/fetchPromptPartials.ts","../src/ai/fetchPrompts.ts","../src/ai/gqls/promptThread.ts","../src/ai/fetchPromptThreads.ts","../src/ai/reportPromptRun.ts","../src/ai/syncAgentFiles.ts","../src/ai/syncAgentFunctions.ts","../src/ai/syncAgents.ts","../src/ai/syncPromptGroups.ts","../src/ai/syncPromptPartials.ts","../src/ai/syncPrompts.ts","../src/assessments/gqls/actionItemCollection.ts","../src/assessments/fetchAllActionItemCollections.ts","../src/assessments/gqls/actionItem.ts","../src/assessments/fetchAllActionItems.ts","../src/assessments/gqls/assessment.ts","../src/assessments/fetchAllAssessments.ts","../src/assessments/parseAssessmentDisplayLogic.ts","../src/assessments/parseAssessmentRiskLogic.ts","../src/assessments/syncActionItemCollections.ts","../src/assessments/syncActionItems.ts","../src/code-intelligence/gqls/codePackage.ts","../src/code-intelligence/fetchAllCodePackages.ts","../src/code-intelligence/gqls/repository.ts","../src/code-intelligence/fetchAllRepositories.ts","../src/code-intelligence/gqls/softwareDevelopmentKit.ts","../src/code-intelligence/fetchAllSoftwareDevelopmentKits.ts","../src/code-intelligence/syncRepositories.ts","../src/code-intelligence/syncSoftwareDevelopmentKits.ts","../src/index.ts"],"sourcesContent":["/**\n * Shared GQL field selection constants and types used across\n * multiple SDK domains (consent, data-inventory, etc.).\n */\n\n/** Owner fields shared across queries */\nexport const OWNER_FIELDS = `\n id\n name\n email\n`;\n\n/** Team fields shared across queries */\nexport const TEAM_FIELDS = `\n id\n name\n`;\n\n/** Attribute value fields (with nested key) shared across queries */\nexport const ATTRIBUTE_VALUE_FIELDS = `\n id\n name\n attributeKey {\n id\n name\n }\n`;\n\n/** Owner assigned to an entity */\nexport interface TranscendOwnerGql {\n /** Owner ID */\n id: string;\n /** Owner display name */\n name: string;\n /** Owner email */\n email: string;\n}\n\n/** Team assigned to an entity */\nexport interface TranscendTeamGql {\n /** Team ID */\n id: string;\n /** Team name */\n name: string;\n}\n\n/** Attribute value on an entity */\nexport interface TranscendAttributeValueGql {\n /** Attribute value ID */\n id: string;\n /** Attribute value name */\n name: string;\n /** Attribute key */\n attributeKey: {\n /** Attribute key ID */\n id: string;\n /** Attribute key name */\n name: string;\n };\n}\n","import { GraphQLClient } from 'graphql-request';\n\n/**\n * Create a GraphQL client\n *\n * @param transcendUrl - Transcend API URL\n * @param headers - Request headers to include in each request\n * @param version - Optional version string to include in request headers\n * @returns GraphQL client\n */\nexport function buildTranscendGraphQLClientGeneric(\n transcendUrl: string,\n headers: Record<string, string>,\n version?: string,\n): GraphQLClient {\n return new GraphQLClient(`${transcendUrl}/graphql`, {\n headers: {\n ...headers,\n ...(version ? { version } : {}),\n },\n });\n}\n\n/**\n * Create a GraphQL client capable of submitting requests with an API key\n *\n * @param transcendUrl - Transcend API URL\n * @param auth - API key to authenticate to API\n * @param version - Optional version string to include in request headers\n * @returns GraphQL client\n */\nexport function buildTranscendGraphQLClient(\n transcendUrl: string,\n auth: string,\n version?: string,\n): GraphQLClient {\n return buildTranscendGraphQLClientGeneric(\n transcendUrl,\n { Authorization: `Bearer ${auth}` },\n version,\n );\n}\n","import { sleepPromise, type Logger } from '@transcend-io/utils';\nimport type { GraphQLClient, RequestDocument, Variables } from 'graphql-request';\n\n/** Logger that silently discards all messages */\nexport const NOOP_LOGGER: Logger = {\n info: () => {},\n warn: () => {},\n error: () => {},\n debug: () => {},\n};\n\nconst DEFAULT_MAX_RETRIES = 4;\n\nconst KNOWN_ERRORS = [\n 'syntax error',\n 'got invalid value',\n 'Client error',\n 'cannot affect row a second time',\n 'GRAPHQL_VALIDATION_FAILED',\n];\n\n/**\n * Make a GraphQL request with retries\n *\n * @param client - GraphQL client\n * @param document - GraphQL document\n * @param options - Options including logger, variables, headers, and retry config\n * @returns Response\n */\nexport async function makeGraphQLRequest<T, V extends Variables = Variables>(\n client: GraphQLClient,\n document: RequestDocument,\n options: {\n /** GraphQL variables */\n variables?: V;\n /** Logger for retry/error messages */\n logger?: Logger;\n /** Additional request headers */\n requestHeaders?: Record<string, string> | string[][] | Headers;\n /** Max number of retry attempts (default 4) */\n maxRetries?: number;\n },\n): Promise<T> {\n const {\n variables,\n logger = NOOP_LOGGER,\n requestHeaders,\n maxRetries = DEFAULT_MAX_RETRIES,\n } = options;\n\n let retryCount = 0;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n try {\n const result = await client.request(document, variables, requestHeaders);\n return result as T;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (err: any) {\n if (err.message?.includes('API key is invalid')) {\n throw new Error(\n 'API key is invalid. ' +\n 'Please ensure that the key provided has the proper scope and is not expired, ' +\n 'and that the transcendUrl corresponds to the correct backend for your organization.',\n );\n }\n\n if (KNOWN_ERRORS.some((msg) => err.message?.includes(msg))) {\n throw err;\n }\n\n if (err.message?.startsWith('Client error: Too many requests')) {\n const rateLimitResetAt = err.response?.headers?.get('x-ratelimit-reset');\n const sleepTime = rateLimitResetAt\n ? new Date(rateLimitResetAt).getTime() - new Date().getTime() + 100\n : 1000 * 10;\n logger.warn(`DETECTED RATE LIMIT: ${err.message}. Sleeping for ${sleepTime}ms`);\n await sleepPromise(sleepTime);\n }\n\n if (retryCount >= maxRetries) {\n throw err;\n }\n retryCount += 1;\n logger.warn(`Retrying failed request (${retryCount} / ${maxRetries}): ${err.message}`);\n }\n }\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const ORGANIZATION: DocumentNode = parse(gql`\n query TranscendCliOrganization {\n organization {\n sombra {\n customerUrl\n }\n }\n }\n`);\n","import type { Logger } from '@transcend-io/utils';\nimport got, { type Got } from 'got';\n\nimport { buildTranscendGraphQLClient } from './buildTranscendGraphQLClient.js';\nimport { ORGANIZATION } from './gqls/organization.js';\nimport { makeGraphQLRequest, NOOP_LOGGER } from './makeGraphQLRequest.js';\n\n/**\n * Instantiate an instance of got that is capable of making requests\n * to a sombra gateway.\n *\n * @param transcendUrl - URL of Transcend API\n * @param transcendApiKey - Transcend API key\n * @param options - Additional options\n * @returns The instance of got that is capable of making requests to the customer ingress\n */\nexport async function createSombraGotInstance(\n transcendUrl: string,\n transcendApiKey: string,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Sombra API key */\n sombraApiKey?: string;\n /** Override Sombra URL (replaces process.env.SOMBRA_URL lookup) */\n sombraUrl?: string;\n } = {},\n): Promise<Got> {\n const { logger = NOOP_LOGGER, sombraApiKey, sombraUrl } = options;\n\n const client = buildTranscendGraphQLClient(transcendUrl, transcendApiKey);\n const { organization } = await makeGraphQLRequest<{\n /** Organization */\n organization: {\n /** Primary Sombra */\n sombra: {\n /** URL */\n customerUrl: string;\n };\n };\n }>(client, ORGANIZATION, { logger });\n\n const { customerUrl } = organization.sombra;\n const sombraToUse = sombraUrl || customerUrl;\n\n if (\n !sombraUrl &&\n [\n 'https://sombra-reverse-tunnel.transcend.io',\n 'https://sombra-reverse-tunnel.us.transcend.io',\n ].includes(customerUrl)\n ) {\n throw new Error(\n 'It looks like your Sombra customer ingress URL has not been set up. ' +\n 'Please follow the instructions here to configure networking for Sombra: ' +\n 'https://docs.transcend.io/docs/articles/sombra/deploying/customizing-sombra/networking',\n );\n }\n logger.info(`Using sombra: ${sombraToUse}`);\n\n return (got as unknown as Got).extend({\n prefixUrl: sombraToUse,\n headers: {\n Authorization: `Bearer ${transcendApiKey}`,\n ...(sombraApiKey ? { 'X-Sombra-Authorization': `Bearer ${sombraApiKey}` } : {}),\n },\n });\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const BUSINESS_ENTITIES = gql`\n query TranscendCliBusinessEntities($first: Int!, $offset: Int!) {\n businessEntities(\n first: $first\n offset: $offset\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n useMaster: false\n ) {\n nodes {\n id\n title\n description\n dataProtectionOfficerName\n dataProtectionOfficerEmail\n address\n headquarterCountry\n headquarterSubDivision\n attributeValues {\n name\n attributeKey {\n name\n }\n }\n }\n }\n }\n`;\n\nexport const CREATE_BUSINESS_ENTITY = gql`\n mutation TranscendCliCreateBusinessEntity($input: CreateBusinessEntityInput!) {\n createBusinessEntity(input: $input) {\n businessEntity {\n id\n title\n description\n dataProtectionOfficerName\n dataProtectionOfficerEmail\n address\n headquarterCountry\n headquarterSubDivision\n attributeValues {\n name\n attributeKey {\n name\n }\n }\n }\n }\n }\n`;\n\nexport const UPDATE_BUSINESS_ENTITIES = gql`\n mutation TranscendCliUpdateBusinessEntities($input: [UpdateBusinessEntityInput!]!) {\n updateBusinessEntities(input: { businessEntities: $input }) {\n clientMutationId\n }\n }\n`;\n","import { IsoCountryCode, IsoCountrySubdivisionCode } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { BUSINESS_ENTITIES } from './gqls/businessEntity.js';\n\nexport interface BusinessEntity {\n /** ID of business entity */\n id: string;\n /** Title of business entity */\n title: string;\n /** Description of business entity */\n description?: string;\n /** Data protection officer name */\n dataProtectionOfficerName?: string;\n /** Data protection officer email */\n dataProtectionOfficerEmail?: string;\n /** Address of business entity */\n address?: string;\n /** Headquarters of business entity */\n headquarterCountry?: IsoCountryCode;\n /** Subdivision of business entity */\n headquarterSubDivision?: IsoCountrySubdivisionCode;\n /** Attributes */\n attributeValues: {\n /** Name of attribute value */\n name: string;\n /** Attribute key */\n attributeKey: {\n /** Name of attribute key */\n name: string;\n };\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all businessEntities in the organization\n *\n * @param client - GraphQL client\n * @returns All businessEntities in the organization\n */\nexport async function fetchAllBusinessEntities(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<BusinessEntity[]> {\n const { logger } = options;\n const businessEntities: BusinessEntity[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n businessEntities: { nodes },\n } = await makeGraphQLRequest<{\n /** Business entities */\n businessEntities: {\n /** List */\n nodes: BusinessEntity[];\n };\n }>(client, BUSINESS_ENTITIES, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n businessEntities.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return businessEntities.sort((a, b) => a.title.localeCompare(b.title));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// orderBy: [\n// { field: createdAt, direction: ASC }\n// { field: name, direction: ASC }\n// ]\nexport const DATA_SUB_CATEGORIES = gql`\n query TranscendCliDataSubCategories($first: Int!, $offset: Int!) {\n dataSubCategories(first: $first, offset: $offset, isExportCsv: true, useMaster: false) {\n nodes {\n id\n name\n category\n description\n regex\n teams {\n name\n }\n owners {\n email\n }\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n }\n }\n }\n`;\n\nexport const CREATE_DATA_SUB_CATEGORY = gql`\n mutation TranscendCliCreateDataSubCategory($input: CreateDataInventorySubCategoryInput!) {\n createDataSubCategory(input: $input) {\n dataSubCategory {\n id\n name\n category\n }\n }\n }\n`;\n\nexport const UPDATE_DATA_SUB_CATEGORIES = gql`\n mutation TranscendCliUpdateDataSubCategories($input: UpdateDataSubCategoriesInput!) {\n updateDataSubCategories(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { DataCategoryType } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { DATA_SUB_CATEGORIES } from './gqls/dataCategory.js';\n\nexport interface DataSubCategory {\n /** ID of data category */\n id: string;\n /** Name of data category */\n name: string;\n /** Type of data category */\n category: DataCategoryType;\n /** Description of data category */\n description?: string;\n /** Regex for data category */\n regex?: string;\n /** Assigned teams */\n teams: {\n /** Team name */\n name: string;\n }[];\n /** Assigned owners */\n owners: {\n /** Email */\n email: string;\n }[];\n /** Custom fields */\n attributeValues: {\n /** Name of attribute value */\n name: string;\n /** Attribute key that the value represents */\n attributeKey: {\n /** Name of attribute team */\n name: string;\n };\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all dataSubCategories in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All dataSubCategories in the organization\n */\nexport async function fetchAllDataCategories(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<DataSubCategory[]> {\n const { logger } = options;\n const dataSubCategories: DataSubCategory[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n dataSubCategories: { nodes },\n } = await makeGraphQLRequest<{\n /** DataCategories */\n dataSubCategories: {\n /** List */\n nodes: DataSubCategory[];\n };\n }>(client, DATA_SUB_CATEGORIES, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n dataSubCategories.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return dataSubCategories.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_POINTS = gql`\n query TranscendCliDataPoints($filterBy: DataPointFiltersInput, $first: Int!, $offset: Int!) {\n dataPoints(\n filterBy: $filterBy\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n title {\n defaultMessage\n }\n description {\n defaultMessage\n }\n owners {\n email\n }\n teams {\n name\n }\n name\n path\n actionSettings {\n type\n active\n }\n dataCollection {\n title {\n defaultMessage\n }\n }\n dbIntegrationQueries {\n query\n suggestedQuery\n requestType\n }\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_POINT_COUNT = gql`\n query TranscendCliDataPointCount($filterBy: DataPointFiltersInput) {\n dataPoints(filterBy: $filterBy, useMaster: false) {\n totalCount\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - add orderBy\n// isExportCsv: true\nexport const SUB_DATA_POINTS = gql`\n query TranscendCliSubDataPoints(\n $filterBy: SubDataPointFiltersInput\n $first: Int!\n $offset: Int!\n ) {\n subDataPoints(filterBy: $filterBy, first: $first, offset: $offset, useMaster: false) {\n nodes {\n id\n name\n description\n purposes {\n name\n purpose\n }\n categories {\n name\n category\n }\n accessRequestVisibilityEnabled\n erasureRequestRedactionEnabled\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n }\n }\n }\n`;\n\nexport const SUB_DATA_POINTS_COUNT = gql`\n query TranscendCliSubDataPointsCount($filterBy: SubDataPointFiltersInput) {\n subDataPoints(filterBy: $filterBy, useMaster: false) {\n totalCount\n }\n }\n`;\n\nexport const SUB_DATA_POINTS_WITH_GUESSES = gql`\n query TranscendCliSubDataPointGuesses(\n $filterBy: SubDataPointFiltersInput\n $first: Int!\n $offset: Int!\n ) {\n subDataPoints(filterBy: $filterBy, first: $first, offset: $offset, useMaster: false) {\n nodes {\n id\n name\n description\n purposes {\n name\n purpose\n }\n categories {\n name\n category\n }\n pendingCategoryGuesses {\n category {\n name\n category\n }\n status\n confidence\n classifierVersion\n }\n accessRequestVisibilityEnabled\n erasureRequestRedactionEnabled\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n }\n }\n }\n`;\n\nexport const UPDATE_OR_CREATE_DATA_POINT = gql`\n mutation TranscendCliUpdateOrCreateDataPoint(\n $dataSiloId: ID!\n $name: String!\n $path: [String!]\n $title: String\n $description: String\n $ownerIds: [ID!]\n $ownerEmails: [String!]\n $teamNames: [String!]\n $teamIds: [ID!]\n $dataCollectionTag: String\n $querySuggestions: [DbIntegrationQuerySuggestionInput!]\n $enabledActions: [RequestActionObjectResolver!]\n $subDataPoints: [DataPointSubDataPointInput!]\n ) {\n updateOrCreateDataPoint(\n input: {\n dataSiloId: $dataSiloId\n name: $name\n path: $path\n title: $title\n teamNames: $teamNames\n ownerEmails: $ownerEmails\n dataCollectionTag: $dataCollectionTag\n description: $description\n ownerIds: $ownerIds\n teamIds: $teamIds\n querySuggestions: $querySuggestions\n enabledActions: $enabledActions\n subDataPoints: $subDataPoints\n }\n ) {\n dataPoint {\n id\n name\n }\n }\n }\n`;\n\nexport const DATAPOINT_EXPORT = gql`\n query TranscendCliDataPointCsvExport($filterBy: DataPointFiltersInput, $first: Int!) {\n dataPoints(filterBy: $filterBy, first: $first, useMaster: false) {\n nodes {\n id\n title {\n defaultMessage\n }\n description {\n defaultMessage\n }\n owners {\n email\n }\n teams {\n name\n }\n name\n path\n }\n }\n }\n`;\n","import {\n ConfidenceLabel,\n DataCategoryType,\n ProcessingPurpose,\n RequestActionObjectResolver,\n SubDataPointDataSubCategoryGuessStatus,\n} from '@transcend-io/privacy-types';\nimport { map, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { sortBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport type { DataSiloAttributeValue } from './fetchAllDataSilos.js';\nimport { DATA_POINTS, SUB_DATA_POINTS, SUB_DATA_POINTS_WITH_GUESSES } from './gqls/dataPoint.js';\n\nexport interface SubDataPointCategory {\n /** Sub-category name */\n name: string;\n /** Top-level category */\n category: DataCategoryType;\n}\n\nexport interface SubDataPointPurpose {\n /** Sub-purpose name */\n name: string;\n /** Top-level purpose */\n purpose: ProcessingPurpose;\n}\n\nexport interface SubDataPoint {\n /** Name (or key) of the subdatapoint */\n name: string;\n /** The description */\n description?: string;\n /** Personal data category */\n categories: SubDataPointCategory[];\n /** The processing purpose for this sub datapoint */\n purposes: SubDataPointPurpose[];\n /**\n * When true, this subdatapoint should be revealed in a data access request.\n * When false, this field should be redacted\n */\n accessRequestVisibilityEnabled: boolean;\n /**\n * When true, this subdatapoint should be redacted during an erasure request.\n * There normally is a choice of enabling hard deletion or redaction at the\n * datapoint level, but if redaction is enabled, this column can be used\n * to define which fields should be redacted.\n */\n erasureRequestRedactionEnabled: boolean;\n /** Attribute attached to subdatapoint */\n attributeValues: DataSiloAttributeValue[];\n /** Data category guesses that are output by the classifier */\n pendingCategoryGuesses?: {\n /** Data category being guessed */\n category: SubDataPointCategory;\n /** Status of guess */\n status: SubDataPointDataSubCategoryGuessStatus;\n /** Confidence level of guess */\n confidence: number;\n /** Confidence label */\n confidenceLabel: ConfidenceLabel;\n /** classifier version that produced the guess */\n classifierVersion: number;\n }[];\n}\n\nexport interface DataPoint {\n /** ID of dataPoint */\n id: string;\n /** Title of dataPoint */\n title: {\n /** Default message */\n defaultMessage: string;\n };\n /** The path to this data point */\n path: string[];\n /** Description */\n description: {\n /** Default message */\n defaultMessage: string;\n };\n /** Name */\n name: string;\n /** Global actions */\n actionSettings: {\n /** Action type */\n type: RequestActionObjectResolver;\n /** Is enabled */\n active: boolean;\n }[];\n /** Data collection tag for privacy request download zip labeling */\n dataCollection?: {\n /** Title of data collection */\n title: {\n /** Default message (since message can be translated) */\n defaultMessage: string;\n };\n };\n /** Metadata for this data silo */\n catalog: {\n /** Whether the data silo supports automated vendor coordination */\n hasAvcFunctionality: boolean;\n };\n /** Owners of the datapoint */\n owners: {\n /** Email address of the owner */\n email: string;\n }[];\n /** Teams that own the datapoint */\n teams: {\n /** Name of the team */\n name: string;\n }[];\n /** Database integration queries */\n dbIntegrationQueries: {\n /** Approved query */\n query: string | null;\n /** Suggested query */\n suggestedQuery: string | null;\n /** Request action */\n requestType: RequestActionObjectResolver;\n }[];\n}\n\nexport interface DataPointWithSubDataPoint extends DataPoint {\n /** The associated subdatapoints */\n subDataPoints: SubDataPoint[];\n}\n\n/**\n * Helper to fetch all subdatapoints for a given datapoint\n *\n * @param client - The GraphQL client\n * @param dataPointId - The datapoint ID\n * @param options - Options\n * @returns The list of subdatapoints\n */\nexport async function fetchAllSubDataPoints(\n client: GraphQLClient,\n options: {\n /** Filter criteria */\n filterBy: {\n /** Datapoint ID to fetch sub-datapoints for */\n dataPointId: string;\n };\n /** Enable debug logging */\n debug?: boolean;\n /** Page size for paginated fetching */\n pageSize: number;\n /** When true, metadata around guessed data categories should be included */\n includeGuessedCategories?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<SubDataPoint[]> {\n const {\n filterBy: { dataPointId },\n debug,\n includeGuessedCategories,\n pageSize,\n logger = NOOP_LOGGER,\n } = options;\n const subDataPoints: SubDataPoint[] = [];\n\n let offset = 0;\n\n let shouldContinue = false;\n do {\n try {\n if (debug) {\n logger.info(`Pulling in subdatapoints for offset ${offset}`);\n }\n const {\n subDataPoints: { nodes },\n } = await makeGraphQLRequest<{\n /** Query response */\n subDataPoints: {\n /** List of matches */\n nodes: SubDataPoint[];\n };\n }>(client, includeGuessedCategories ? SUB_DATA_POINTS_WITH_GUESSES : SUB_DATA_POINTS, {\n variables: {\n first: pageSize,\n filterBy: {\n dataPoints: [dataPointId],\n },\n offset,\n },\n logger,\n });\n\n subDataPoints.push(...nodes);\n offset += pageSize;\n shouldContinue = nodes.length === pageSize;\n\n if (debug) {\n logger.info(`Pulled in subdatapoints for offset ${offset} for dataPointId=${dataPointId}`);\n }\n } catch (err) {\n logger.error(\n `An error fetching subdatapoints for offset ${offset} for dataPointId=${dataPointId}`,\n );\n throw err;\n }\n } while (shouldContinue);\n return sortBy(subDataPoints, 'name');\n}\n\n/**\n * Fetch all datapoints for a data silo\n *\n * @param client - GraphQL client\n * @param dataSiloId - Data silo ID\n * @param options - Options\n * @returns List of datapoints\n */\nexport async function fetchAllDataPoints(\n client: GraphQLClient,\n options: {\n /** Filter criteria */\n filterBy: {\n /** Data silo ID to fetch datapoints for */\n dataSiloId: string;\n };\n /** Enable debug logging */\n debug?: boolean;\n /** Page size for paginated fetching */\n pageSize: number;\n /** Skip fetching of subdatapoints */\n skipSubDatapoints?: boolean;\n /** When true, metadata around guessed data categories should be included */\n includeGuessedCategories?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<DataPointWithSubDataPoint[]> {\n const {\n filterBy: { dataSiloId },\n debug,\n pageSize,\n skipSubDatapoints,\n includeGuessedCategories,\n logger = NOOP_LOGGER,\n } = options;\n const dataPoints: DataPointWithSubDataPoint[] = [];\n\n // TODO: https://transcend.height.app/T-40481 - add cursor pagination\n let offset = 0;\n\n let shouldContinue = false;\n do {\n if (debug) {\n logger.info(`Fetching datapoints with offset: ${offset}`);\n }\n\n const {\n dataPoints: { nodes },\n } = await makeGraphQLRequest<{\n /** Query response */\n dataPoints: {\n /** List of matches */\n nodes: DataPoint[];\n };\n }>(client, DATA_POINTS, {\n variables: {\n first: pageSize,\n filterBy: {\n dataSilos: [dataSiloId],\n },\n offset,\n },\n logger,\n });\n\n if (debug) {\n logger.info(`Fetched ${nodes.length} datapoints at offset: ${offset}`);\n }\n\n if (!skipSubDatapoints) {\n await map(\n nodes,\n async (node) => {\n try {\n if (debug) {\n logger.info(`Fetching subdatapoints for ${node.name} for datapoint offset ${offset}`);\n }\n\n const subDataPoints = await fetchAllSubDataPoints(client, {\n filterBy: { dataPointId: node.id },\n pageSize: 1000,\n debug,\n includeGuessedCategories,\n logger,\n });\n dataPoints.push({\n ...node,\n subDataPoints: subDataPoints.sort((a, b) => a.name.localeCompare(b.name)),\n });\n\n if (debug) {\n logger.info(`Successfully fetched subdatapoints for ${node.name}`);\n }\n } catch (err) {\n logger.error(\n `An error fetching subdatapoints for ${node.name} datapoint offset ${offset}`,\n );\n throw err;\n }\n },\n {\n concurrency: 5,\n },\n );\n\n if (debug) {\n logger.info(`Fetched all subdatapoints for page of datapoints at offset: ${offset}`);\n }\n }\n\n offset += pageSize;\n shouldContinue = nodes.length === pageSize;\n } while (shouldContinue);\n return dataPoints.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_SILOS = gql`\n query TranscendCliDataSilos($filterBy: DataSiloFiltersInput!, $first: Int!, $offset: Int!) {\n dataSilos(\n filterBy: $filterBy\n first: $first\n offset: $offset\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n useMaster: false\n ) {\n nodes {\n id\n title\n link\n type\n catalog {\n hasAvcFunctionality\n }\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_SILO_EXPORT = gql`\n query TranscendCliDataSiloExport($filterBy: DataSiloFiltersInput!, $first: Int!) {\n dataSilos(filterBy: $filterBy, first: $first, useMaster: false) {\n nodes {\n id\n title\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_SILOS_ENRICHED = gql`\n query TranscendCliDataSilosEnriched(\n $filterBy: DataSiloFiltersInput!\n $first: Int!\n $offset: Int!\n ) {\n dataSilos(\n filterBy: $filterBy\n first: $first\n offset: $offset\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n useMaster: false\n ) {\n nodes {\n id\n title\n description\n type\n outerType\n link\n country\n countrySubDivision\n url\n notifyEmailAddress\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n apiKeys {\n title\n }\n subjectBlocklist {\n type\n }\n identifiers {\n name\n isConnected\n }\n dependentDataSilos {\n title\n }\n owners {\n email\n }\n teams {\n id\n name\n }\n catalog {\n hasAvcFunctionality\n }\n isLive\n promptAVendorEmailSendFrequency\n promptAVendorEmailSendType\n promptAVendorEmailIncludeIdentifiersAttachment\n promptAVendorEmailCompletionLinkType\n manualWorkRetryFrequency\n discoveredBy {\n title\n }\n businessEntities {\n title\n }\n }\n }\n }\n`;\n\nexport const UPDATE_DATA_SILOS = gql`\n mutation TranscendCliUpdateDataSilo($input: UpdateDataSilosInput!) {\n updateDataSilos(input: $input) {\n clientMutationId\n dataSilos {\n id\n title\n }\n }\n }\n`;\n\nexport const CREATE_DATA_SILOS = gql`\n mutation TranscendCliCreateDataSilo($input: [CreateDataSilosInput!]!) {\n createDataSilos(input: $input) {\n dataSilos {\n id\n title\n }\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport type { DataSiloAttributeValue } from '../dsr-automation/formatAttributeValues.js';\nimport { DATA_SILOS } from './gqls/dataSilo.js';\n\nexport type { DataSiloAttributeValue };\n\nexport interface DataSilo {\n /** ID of dataSilo */\n id: string;\n /** Title of dataSilo */\n title: string;\n /** Type of silo */\n type: string;\n /** The link to the data silo */\n link: string;\n /** Attribute labels */\n attributeValues: DataSiloAttributeValue[];\n /** description */\n description: string;\n /** Metadata for this data silo */\n catalog: {\n /** Whether the data silo supports automated vendor coordination */\n hasAvcFunctionality: boolean;\n };\n}\n\n/**\n * Fetch all dataSilos in the organization\n *\n * @param client - GraphQL client\n * @param options - Filter and pagination options\n * @returns All dataSilos in the organization\n */\nexport async function fetchAllDataSilos<TDataSilo extends DataSilo>(\n client: GraphQLClient,\n options: {\n /** Page size to fetch data silos in */\n pageSize: number;\n /** Filter by title */\n titles?: string[];\n /** Filter by IDs */\n ids?: string[];\n /** Set of integration names to fetch */\n integrationNames?: string[];\n /** GQL query override for data silos */\n gql?: string;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<TDataSilo[]> {\n const {\n titles,\n pageSize,\n ids = [],\n gql = DATA_SILOS,\n integrationNames = [],\n logger = NOOP_LOGGER,\n } = options;\n\n logger.info(`Fetching ${ids.length === 0 ? 'all' : ids.length} Data Silos...`);\n\n const dataSilos: TDataSilo[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n dataSilos: { nodes },\n } = await makeGraphQLRequest<{\n /** Query response */\n dataSilos: {\n /** List of matches */\n nodes: TDataSilo[];\n };\n }>(client, gql, {\n variables: {\n filterBy: {\n ids: ids.length > 0 ? ids : undefined,\n type: integrationNames.length > 0 ? integrationNames : undefined,\n titles,\n },\n first: pageSize,\n offset,\n },\n logger,\n });\n dataSilos.push(...nodes);\n offset += pageSize;\n shouldContinue = nodes.length === pageSize;\n } while (shouldContinue);\n\n logger.info(\n `Found a total of ${dataSilos.length} data silo${\n ids.length > 0 ? ` matching IDs ${ids.join(',')}` : ''\n }s${\n integrationNames.length > 0 ? ` matching integrationNames ${integrationNames.join(',')}` : ''\n }`,\n );\n\n return dataSilos.sort((a, b) => a.title.localeCompare(b.title));\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const IDENTIFIERS: DocumentNode = parse(gql`\n query TranscendCliIdentifiers($first: Int!, $offset: Int!) {\n identifiers(\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n type\n regex\n selectOptions\n privacyCenterVisibility\n dataSubjects {\n type\n }\n isRequiredInForm\n placeholder\n displayTitle {\n defaultMessage\n }\n displayDescription {\n defaultMessage\n }\n displayOrder\n isUniqueOnPreferenceStore\n }\n }\n }\n`);\n","import { IdentifierType, RequestAction } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { IDENTIFIERS } from './gqls/identifier.js';\n\nexport interface Identifier {\n /** ID of identifier */\n id: string;\n /** Name of identifier */\n name: string;\n /** The type of identifier */\n type: IdentifierType;\n /** Regular expression */\n regex: string;\n /** The set of options that the identifier supports */\n selectOptions: string[];\n /** Whether identifier is enabled on privacy center */\n privacyCenterVisibility: RequestAction[];\n /** Enabled data subjects that are exposed this identifier on the privacy center */\n dataSubjects: {\n /** type of data subjects */\n type: string;\n }[];\n /** Whether identifier is a required field in privacy center form */\n isRequiredInForm: boolean;\n /** Identifier placeholder text */\n placeholder: string;\n /** Display title for identifier */\n displayTitle: {\n /** Default message */\n defaultMessage: string;\n };\n /** Display description for identifier */\n displayDescription: {\n /** Default */\n defaultMessage: string;\n };\n /** Display order */\n displayOrder: number;\n /** Does this identifier uniquely identify a consent record */\n isUniqueOnPreferenceStore: boolean;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all identifiers in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All identifiers in the organization\n */\nexport async function fetchAllIdentifiers(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Identifier[]> {\n const { logger } = options;\n const identifiers: Identifier[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n identifiers: { nodes },\n } = await makeGraphQLRequest<{\n /** Identifiers */\n identifiers: {\n /** List */\n nodes: Identifier[];\n };\n }>(client, IDENTIFIERS, {\n logger,\n variables: { first: PAGE_SIZE, offset },\n });\n identifiers.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return identifiers.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\nexport const PROCESSING_ACTIVITIES = gql`\n query TranscendCliProcessingActivities($first: Int!, $offset: Int!) {\n processingActivities(first: $first, offset: $offset, useMaster: false) {\n nodes {\n id\n title\n description\n securityMeasureDetails\n controllerships\n storageRegions {\n countrySubDivision\n country\n }\n transferRegions {\n countrySubDivision\n country\n }\n retentionType\n retentionPeriod\n dataProtectionImpactAssessmentLink\n dataProtectionImpactAssessmentStatus\n attributeValues {\n name\n attributeKey {\n name\n }\n }\n dataSilos {\n title\n }\n dataSubjects {\n type\n }\n teams {\n name\n }\n owners {\n email\n }\n processingPurposeSubCategories {\n name\n purpose\n }\n dataSubCategories {\n name\n category\n }\n saaSCategories {\n title\n }\n }\n }\n }\n`;\n\nexport const CREATE_PROCESSING_ACTIVITY = gql`\n mutation TranscendCliCreateProcessingActivity($input: CreateProcessingActivityInput!) {\n createProcessingActivity(input: $input) {\n processingActivity {\n id\n title\n }\n }\n }\n`;\n\nexport const UPDATE_PROCESSING_ACTIVITIES = gql`\n mutation TranscendCliUpdateProcessingActivities($input: UpdateProcessingActivitiesInput!) {\n updateProcessingActivities(input: $input) {\n clientMutationId\n }\n }\n`;\n","import type {\n ProcessingPurpose,\n DataCategoryType,\n DataProtectionImpactAssessmentStatus,\n Controllership,\n RetentionType,\n} from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport type { Region } from '../administration/formatRegions.js';\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PROCESSING_ACTIVITIES } from './gqls/processingActivity.js';\n\nexport interface ProcessingActivity {\n /** ID of processing activity */\n id: string;\n /** Title of processing activity */\n title: string;\n /** Description of processing activity */\n description: string;\n /** Security measure details */\n securityMeasureDetails?: string;\n /** Controllerships */\n controllerships: Controllership[];\n /** Storage regions */\n storageRegions: Region[];\n /** Transfer regions */\n transferRegions: Region[];\n /** Retention type */\n retentionType: RetentionType;\n /** Retention period in days */\n retentionPeriod?: number;\n /** Data protection impact assessment link */\n dataProtectionImpactAssessmentLink?: string;\n /** Data protection impact assessment status */\n dataProtectionImpactAssessmentStatus: DataProtectionImpactAssessmentStatus;\n /** Attribute values */\n attributeValues: {\n /** Name of attribute value */\n name: string;\n /** Attribute key */\n attributeKey: {\n /** Name of attribute key */\n name: string;\n };\n }[];\n /** Data silos */\n dataSilos: {\n /** Data silo title */\n title: string;\n }[];\n /** Data subjects */\n dataSubjects: {\n /** Data subject type */\n type: string;\n }[];\n /** Teams */\n teams: {\n /** Team name */\n name: string;\n }[];\n /** Owners */\n owners: {\n /** Owner email */\n email: string;\n }[];\n /** Processing purpose sub categories */\n processingPurposeSubCategories: {\n /** Processing purpose sub category name */\n name: string;\n /** Processing purpose */\n purpose: ProcessingPurpose;\n }[];\n /** Data sub categories */\n dataSubCategories: {\n /** Data sub category name */\n name: string;\n /** Data category */\n category: DataCategoryType;\n }[];\n /** SaaS categories */\n saaSCategories: {\n /** Title */\n title: string;\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all processingActivities in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All processingActivities in the organization\n */\nexport async function fetchAllProcessingActivities(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<ProcessingActivity[]> {\n const { logger } = options;\n const processingActivities: ProcessingActivity[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n processingActivities: { nodes },\n } = await makeGraphQLRequest<{\n /** Processing activities */\n processingActivities: {\n /** List */\n nodes: ProcessingActivity[];\n };\n }>(client, PROCESSING_ACTIVITIES, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n processingActivities.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return processingActivities.sort((a, b) => a.title.localeCompare(b.title));\n}\n","import { gql } from 'graphql-request';\n\nexport const VENDORS = gql`\n query TranscendCliVendors($first: Int!, $offset: Int!) {\n vendors(\n first: $first\n offset: $offset\n useMaster: false\n isExportCsv: true\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n ) {\n nodes {\n id\n title\n description\n dataProcessingAgreementLink\n contactName\n contactEmail\n contactPhone\n address\n headquarterCountry\n headquarterSubDivision\n websiteUrl\n businessEntity {\n title\n }\n teams {\n name\n }\n owners {\n email\n }\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n }\n }\n }\n`;\n\nexport const CREATE_VENDOR = gql`\n mutation TranscendCliCreateVendor($input: CreateVendorInput!) {\n createVendor(input: $input) {\n vendor {\n id\n title\n }\n }\n }\n`;\n\nexport const UPDATE_VENDORS = gql`\n mutation TranscendCliUpdateVendor($input: UpdateVendorsInput!) {\n updateVendors(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { IsoCountryCode, IsoCountrySubdivisionCode } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { VENDORS } from './gqls/vendor.js';\n\nexport interface Vendor {\n /** ID of vendor */\n id: string;\n /** Title of vendor */\n title: string;\n /** Description of vendor */\n description: string;\n /** DPA link */\n dataProcessingAgreementLink?: string;\n /** Contract email */\n contactName?: string;\n /** Contract phone */\n contactPhone?: string;\n /** Address */\n address?: string;\n /** Headquarters country */\n headquarterCountry?: IsoCountryCode;\n /** Headquarters subdivision */\n headquarterSubDivision?: IsoCountrySubdivisionCode;\n /** Website URL */\n websiteUrl?: string;\n /** Business entity */\n businessEntity?: {\n /** Business entity title */\n title: string;\n };\n /** Assigned teams */\n teams: {\n /** Team name */\n name: string;\n }[];\n /** Assigned owners */\n owners: {\n /** Email */\n email: string;\n }[];\n /** Custom fields */\n attributeValues: {\n /** Name of attribute value */\n name: string;\n /** Attribute key that the value represents */\n attributeKey: {\n /** Name of attribute team */\n name: string;\n };\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all vendors in the organization\n *\n * @param client - GraphQL client\n * @returns All vendors in the organization\n */\nexport async function fetchAllVendors(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Vendor[]> {\n const { logger } = options;\n const vendors: Vendor[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n vendors: { nodes },\n } = await makeGraphQLRequest<{\n /** Vendors */\n vendors: {\n /** List */\n nodes: Vendor[];\n };\n }>(client, VENDORS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n vendors.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return vendors.sort((a, b) => a.title.localeCompare(b.title));\n}\n","import {\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n PromptAVendorEmailCompletionLinkType,\n PromptAVendorEmailSendType,\n} from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllDataPoints, type DataPointWithSubDataPoint } from './fetchAllDataPoints.js';\nimport { fetchAllDataSilos, type DataSiloAttributeValue } from './fetchAllDataSilos.js';\nimport { DATA_SILOS_ENRICHED } from './gqls/dataSilo.js';\n\nexport interface DataSiloEnriched {\n /** ID of dataSilo */\n id: string;\n /** Title of dataSilo */\n title: string;\n /** Type of silo */\n type: string;\n /** Link to silo */\n link: string;\n /** Outer type of silo */\n outerType: string;\n /** Description of data silo */\n description: string;\n /** Webhook URL */\n url?: string;\n /** Email address of user to notify for prompt a person use case */\n notifyEmailAddress?: string;\n /** Associated API keys */\n apiKeys: {\n /** Title */\n title: string;\n }[];\n /** Data subject block list */\n subjectBlocklist: {\n /** Type of data subject */\n type: string;\n }[];\n /** Identifiers */\n identifiers: {\n /** Name of identifier */\n name: string;\n /** True if identifier is wired */\n isConnected: boolean;\n }[];\n /** Dependent data silos */\n dependentDataSilos: {\n /** Title of silo */\n title: string;\n }[];\n /** Silo owners */\n owners: {\n /** Email owners */\n email: string;\n }[];\n /** The teams assigned to this data silo */\n teams: {\n /** Name of the team assigned to this data silo */\n name: string;\n }[];\n /** Metadata for this data silo */\n catalog: {\n /** Whether the data silo supports automated vendor coordination */\n hasAvcFunctionality: boolean;\n };\n /** Silo is live */\n isLive: boolean;\n /** Hosting country of data silo */\n country?: IsoCountryCode;\n /** Hosting subdivision data silo */\n countrySubDivision?: IsoCountrySubdivisionCode;\n /**\n * The frequency with which we should be sending emails for this data silo, in milliseconds.\n */\n promptAVendorEmailSendFrequency: number;\n /**\n * The type of emails to send for this data silo, i.e. send an email for each DSR, across all open DSRs,\n * or per profile in a DSR.\n */\n promptAVendorEmailSendType: PromptAVendorEmailSendType;\n /**\n * Indicates whether prompt-a-vendor emails should include a list of identifiers\n * in addition to a link to the bulk processing UI.\n */\n promptAVendorEmailIncludeIdentifiersAttachment: boolean;\n /**\n * Indicates what kind of link to generate as part of the emails sent out for this Prompt-a-Vendor silo.\n */\n promptAVendorEmailCompletionLinkType: PromptAVendorEmailCompletionLinkType;\n /**\n * The frequency with which we should retry sending emails for this data silo, in milliseconds.\n * Needs to be a string because the number can be larger than the MAX_INT\n */\n manualWorkRetryFrequency: string;\n /** Attribute values tagged to data silo */\n attributeValues: DataSiloAttributeValue[];\n /**\n * The data silos that discovered this particular data silo\n */\n discoveredBy: {\n /** Title of data silo */\n title: string;\n }[];\n /**\n * The business entities assigned directly to this data silo\n */\n businessEntities: {\n /** Title of business entity */\n title: string;\n }[];\n}\n\n/**\n * Fetch all dataSilos with additional metadata\n *\n * @param client - GraphQL client\n * @param options - Filter options\n * @returns All dataSilos in the organization\n */\nexport async function fetchEnrichedDataSilos(\n client: GraphQLClient,\n options: {\n /** Page size */\n pageSize: number;\n /** Filter by IDs */\n ids?: string[];\n /** Enable debug logs */\n debug?: boolean;\n /** Filter by title */\n titles?: string[];\n /** Integration names */\n integrationNames?: string[];\n /** Skip fetching of datapoints */\n skipDatapoints?: boolean;\n /** Skip fetching of subdatapoints */\n skipSubDatapoints?: boolean;\n /** When true, metadata around guessed data categories should be included */\n includeGuessedCategories?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<[DataSiloEnriched, DataPointWithSubDataPoint[]][]> {\n const {\n ids,\n pageSize,\n titles,\n debug,\n skipDatapoints,\n skipSubDatapoints,\n includeGuessedCategories,\n integrationNames,\n logger = NOOP_LOGGER,\n } = options;\n\n const dataSilos: [DataSiloEnriched, DataPointWithSubDataPoint[]][] = [];\n\n const silos = await fetchAllDataSilos<DataSiloEnriched>(client, {\n titles,\n ids,\n integrationNames,\n pageSize,\n gql: DATA_SILOS_ENRICHED,\n logger,\n });\n\n if (!skipDatapoints) {\n await mapSeries(silos, async (silo, index) => {\n logger.info(`[${index + 1}/${silos.length}] Fetching data silo - ${silo.title}`);\n\n const dataPoints = await fetchAllDataPoints(client, {\n filterBy: { dataSiloId: silo.id },\n debug,\n pageSize,\n skipSubDatapoints,\n includeGuessedCategories,\n logger,\n });\n\n if (debug) {\n logger.info(\n `[${index + 1}/${silos.length}] Successfully fetched datapoint for - ${silo.title}`,\n );\n }\n\n dataSilos.push([silo, dataPoints]);\n });\n }\n\n logger.info(`Successfully fetched all ${silos.length} data silo configurations`);\n\n return dataSilos;\n}\n","import { IsoCountryCode, IsoCountrySubdivisionCode } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy, chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllBusinessEntities, type BusinessEntity } from './fetchAllBusinessEntities.js';\nimport { UPDATE_BUSINESS_ENTITIES, CREATE_BUSINESS_ENTITY } from './gqls/businessEntity.js';\n\nexport interface BusinessEntityInput {\n /** Display title of the business entity */\n title: string;\n /** Description of the business entity */\n description?: string;\n /** Physical address */\n address?: string;\n /** Headquarters country */\n headquarterCountry?: IsoCountryCode;\n /** Headquarters country subdivision */\n headquarterSubDivision?: IsoCountrySubdivisionCode;\n /** Name of the data protection officer */\n dataProtectionOfficerName?: string;\n /** Email of the data protection officer */\n dataProtectionOfficerEmail?: string;\n /** Custom attribute values to assign */\n attributes?: {\n /** Attribute key name */\n key: string;\n /** Attribute values */\n values: string[];\n }[];\n /** Team names to assign */\n teams?: string[];\n /** Owner email addresses to assign */\n owners?: string[];\n}\n\n/**\n * Input to create a new business entity\n *\n * @param client - GraphQL client\n * @param businessEntity - Input\n * @returns Created business entity\n */\nexport async function createBusinessEntity(\n client: GraphQLClient,\n options: {\n /** Business entity to create */\n input: BusinessEntityInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<BusinessEntity> {\n const { input: businessEntity, logger = NOOP_LOGGER } = options;\n const input = {\n title: businessEntity.title,\n description: businessEntity.description,\n address: businessEntity.address,\n headquarterCountry: businessEntity.headquarterCountry,\n headquarterSubDivision: businessEntity.headquarterSubDivision,\n dataProtectionOfficerName: businessEntity.dataProtectionOfficerName,\n dataProtectionOfficerEmail: businessEntity.dataProtectionOfficerEmail,\n attributes: businessEntity.attributes,\n teamNames: businessEntity.teams,\n ownerEmails: businessEntity.owners,\n };\n\n const { createBusinessEntity } = await makeGraphQLRequest<{\n /** Create business entity mutation */\n createBusinessEntity: {\n /** Created business entity */\n businessEntity: BusinessEntity;\n };\n }>(client, CREATE_BUSINESS_ENTITY, {\n variables: { input },\n logger,\n });\n return createBusinessEntity.businessEntity;\n}\n\n/**\n * Input to update business entities\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateBusinessEntities(\n client: GraphQLClient,\n options: {\n /** [BusinessEntityInput, businessEntityId] list */\n input: [BusinessEntityInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: businessEntities, logger = NOOP_LOGGER } = options;\n const chunkedUpdates = chunk(businessEntities, 100);\n await mapSeries(chunkedUpdates, async (chunked) => {\n await makeGraphQLRequest(client, UPDATE_BUSINESS_ENTITIES, {\n variables: {\n input: chunked.map(([businessEntity, id]) => ({\n id,\n title: businessEntity.title,\n description: businessEntity.description,\n address: businessEntity.address,\n headquarterCountry: businessEntity.headquarterCountry,\n headquarterSubDivision: businessEntity.headquarterSubDivision,\n dataProtectionOfficerName: businessEntity.dataProtectionOfficerName,\n dataProtectionOfficerEmail: businessEntity.dataProtectionOfficerEmail,\n attributes: businessEntity.attributes,\n teamNames: businessEntity.teams,\n ownerEmails: businessEntity.owners,\n })),\n },\n logger,\n });\n });\n}\n\n/**\n * Sync the data inventory business entities\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncBusinessEntities(\n client: GraphQLClient,\n inputs: BusinessEntityInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n // Fetch existing\n logger.info(`Syncing \"${inputs.length}\" business entities...`);\n\n let encounteredError = false;\n\n // Fetch existing\n const existingBusinessEntities = await fetchAllBusinessEntities(client, { logger });\n\n // Look up by title\n const businessEntityByTitle = keyBy(existingBusinessEntities, 'title');\n\n // Create new business entities\n const newBusinessEntities = inputs.filter((input) => !businessEntityByTitle[input.title]);\n\n // Create new business entities\n await mapSeries(newBusinessEntities, async (businessEntity) => {\n try {\n const newBusinessEntity = await createBusinessEntity(client, {\n input: businessEntity,\n logger,\n });\n businessEntityByTitle[newBusinessEntity.title] = newBusinessEntity;\n logger.info(`Successfully synced business entity \"${businessEntity.title}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to sync business entity \"${businessEntity.title}\"! - ${(err as Error).message}`,\n );\n }\n });\n\n // Update all business entities\n try {\n logger.info(`Updating \"${inputs.length}\" business entities!`);\n await updateBusinessEntities(client, {\n input: inputs.map((input) => [input, businessEntityByTitle[input.title]!.id]),\n logger,\n });\n logger.info(`Successfully synced \"${inputs.length}\" business entities!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to sync \"${inputs.length}\" business entities ! - ${(err as Error).message}`,\n );\n }\n\n return !encounteredError;\n}\n","import { DataCategoryType } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllDataCategories, type DataSubCategory } from './fetchAllDataCategories.js';\nimport { UPDATE_DATA_SUB_CATEGORIES, CREATE_DATA_SUB_CATEGORY } from './gqls/dataCategory.js';\n\nexport interface DataCategoryInput {\n /** Name of data category */\n name: string;\n /** Type of data category */\n category: DataCategoryType;\n /** Description of data category */\n description?: string;\n /** Regex for data category */\n regex?: string;\n /** Owner email addresses to assign */\n owners?: string[];\n /** Team names to assign */\n teams?: string[];\n /** Attribute value and its corresponding attribute key */\n attributes?: {\n /** Attribute key */\n key: string;\n /** Attribute values */\n values: string[];\n }[];\n}\n\n/**\n * Create a new data category\n *\n * @param client - GraphQL client\n * @param dataCategory - Input\n * @param options - Options\n * @returns Created data category\n */\nexport async function createDataCategory(\n client: GraphQLClient,\n options: {\n /** Data category to create */\n input: DataCategoryInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<DataSubCategory, 'id' | 'name' | 'category'>> {\n const { input: dataCategory, logger = NOOP_LOGGER } = options;\n const input = {\n name: dataCategory.name,\n category: dataCategory.category,\n description: dataCategory.description,\n // TODO: https://transcend.height.app/T-31994 - add attributes, teams, owners\n };\n\n const { createDataCategory } = await makeGraphQLRequest<{\n /** Create data category mutation */\n createDataCategory: {\n /** Created data category */\n dataCategory: DataSubCategory;\n };\n }>(client, CREATE_DATA_SUB_CATEGORY, {\n variables: { input },\n logger,\n });\n return createDataCategory.dataCategory;\n}\n\n/**\n * Update data categories\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateDataCategories(\n client: GraphQLClient,\n options: {\n /** [DataCategoryInput, dataCategoryId] list */\n input: [DataCategoryInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: dataCategories, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_DATA_SUB_CATEGORIES, {\n variables: {\n input: {\n dataSubCategories: dataCategories.map(([dataCategory, id]) => ({\n id,\n description: dataCategory.description,\n // TODO: https://transcend.height.app/T-31994 - add teams, owners\n attributes: dataCategory.attributes,\n })),\n },\n },\n logger,\n });\n}\n\n/**\n * Sync the data inventory data categories\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncDataCategories(\n client: GraphQLClient,\n inputs: DataCategoryInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n logger.info(`Syncing \"${inputs.length}\" data categories...`);\n\n let encounteredError = false;\n\n // Fetch existing\n const existingDataCategories = await fetchAllDataCategories(client, {\n logger,\n });\n\n // Look up by name\n const dataCategoryByName: {\n [k in string]: Pick<DataSubCategory, 'id' | 'name' | 'category'>;\n } = keyBy(existingDataCategories, ({ name, category }) => `${name}:${category}`);\n\n // Create new data categories\n const newDataCategories = inputs.filter(\n (input) => !dataCategoryByName[`${input.name}:${input.category}`],\n );\n\n await mapSeries(newDataCategories, async (dataCategory) => {\n try {\n const newDataCategory = await createDataCategory(client, { input: dataCategory, logger });\n dataCategoryByName[`${newDataCategory.name}:${newDataCategory.category}`] = newDataCategory;\n logger.info(`Successfully synced data category \"${dataCategory.name}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to sync data category \"${dataCategory.name}\"! - ${(err as Error).message}`,\n );\n }\n });\n\n // Update all data categories\n try {\n logger.info(`Updating \"${inputs.length}\" data categories!`);\n await updateDataCategories(client, {\n input: inputs.map((input) => [\n input,\n dataCategoryByName[`${input.name}:${input.category}`]!.id,\n ]),\n logger,\n });\n logger.info(`Successfully synced \"${inputs.length}\" data categories!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync \"${inputs.length}\" data categories ! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport type { DataSilo } from './fetchAllDataSilos.js';\nimport { UPDATE_DATA_SILOS } from './gqls/dataSilo.js';\n\nconst BATCH_SILOS_LIMIT = 20;\n\n/**\n * Sync data silo dependencies\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns True upon success\n */\nexport async function syncDataSiloDependencies(\n client: GraphQLClient,\n options: {\n /** Pairs of [data silo ID, dependency titles] */\n input: [string, string[]][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<boolean> {\n const { input: dependencyUpdates, logger = NOOP_LOGGER } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${dependencyUpdates.length}\" data silo dependencies...`);\n\n const chunkedUpdates = chunk(dependencyUpdates, BATCH_SILOS_LIMIT);\n await mapSeries(chunkedUpdates, async (dependencyUpdateChunk, ind) => {\n logger.info(\n `[Batch ${ind}/${dependencyUpdateChunk.length}] Updating \"${dependencyUpdateChunk.length}\" data silos...`,\n );\n try {\n await makeGraphQLRequest<{\n /** Mutation result */\n updateDataSilos: {\n /** New data silos */\n dataSilos: Pick<DataSilo, 'id' | 'title'>[];\n };\n }>(client, UPDATE_DATA_SILOS, {\n variables: {\n input: {\n dataSilos: dependencyUpdateChunk.map(([id, dependedOnDataSiloTitles]) => ({\n id,\n dependedOnDataSiloTitles,\n })),\n },\n },\n logger,\n });\n logger.info(\n `[Batch ${ind + 1}/${dependencyUpdateChunk.length}] ` +\n `Synced \"${dependencyUpdateChunk.length}\" data silos!`,\n );\n } catch (err) {\n encounteredError = true;\n logger.error(\n `[Batch ${ind + 1}/${dependencyUpdateChunk.length}] ` +\n `Failed to update \"${dependencyUpdateChunk.length}\" silos! - ${(err as Error).message}`,\n );\n }\n });\n return !encounteredError;\n}\n","import type {\n ProcessingPurpose,\n DataCategoryType,\n DataProtectionImpactAssessmentStatus,\n Controllership,\n RetentionType,\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n} from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport {\n fetchAllProcessingActivities,\n type ProcessingActivity,\n} from './fetchAllProcessingActivities.js';\nimport {\n UPDATE_PROCESSING_ACTIVITIES,\n CREATE_PROCESSING_ACTIVITY,\n} from './gqls/processingActivity.js';\n\nexport interface ProcessingActivityInput {\n /** The title of the processing activity */\n title: string;\n /** Description of the processing activity */\n description?: string;\n /** Security measure details */\n securityMeasureDetails?: string;\n /** Controllerships */\n controllerships?: Controllership[];\n /** Storage regions */\n storageRegions?: {\n /** The country */\n country?: IsoCountryCode;\n /** The country subdivision */\n countrySubDivision?: IsoCountrySubdivisionCode;\n }[];\n /** Transfer regions */\n transferRegions?: {\n /** The country */\n country?: IsoCountryCode;\n /** The country subdivision */\n countrySubDivision?: IsoCountrySubdivisionCode;\n }[];\n /** Retention type */\n retentionType?: RetentionType;\n /** Retention period in days */\n retentionPeriod?: number;\n /** Data protection impact assessment link */\n dataProtectionImpactAssessmentLink?: string;\n /** Data protection impact assessment status */\n dataProtectionImpactAssessmentStatus?: DataProtectionImpactAssessmentStatus;\n /** Attribute value and its corresponding attribute key */\n attributes?: {\n /** Attribute key */\n key: string;\n /** Attribute values */\n values: string[];\n }[];\n /** Data silo titles */\n dataSiloTitles?: string[];\n /** Data subject types */\n dataSubjectTypes?: string[];\n /** Team names */\n teamNames?: string[];\n /** Owner emails */\n ownerEmails?: string[];\n /** Processing sub purposes */\n processingSubPurposes?: {\n /** The parent purpose */\n purpose: ProcessingPurpose;\n /** User-defined name for this processing purpose sub category */\n name?: string;\n }[];\n /** Data sub categories */\n dataSubCategories?: {\n /** The parent category */\n category: DataCategoryType;\n /** User-defined name for this sub category */\n name?: string;\n }[];\n /** SaaS category titles */\n saaSCategories?: string[];\n}\n\n/**\n * Create a new processing activity, setting only title and description\n *\n * @param client - GraphQL client\n * @param processingActivity - Input\n * @param options - Options\n * @returns Created processingActivity\n */\nasync function createProcessingActivity(\n client: GraphQLClient,\n processingActivity: ProcessingActivityInput,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Pick<ProcessingActivity, 'id' | 'title'>> {\n const { logger = NOOP_LOGGER } = options;\n const input = {\n title: processingActivity.title,\n description: processingActivity.description,\n };\n\n const { createProcessingActivity } = await makeGraphQLRequest<{\n /** Create processingActivity mutation */\n createProcessingActivity: {\n /** Created processingActivity */\n processingActivity: ProcessingActivity;\n };\n }>(client, CREATE_PROCESSING_ACTIVITY, {\n variables: { input },\n logger,\n });\n return createProcessingActivity.processingActivity;\n}\n\n/**\n * Update a list of processing activities.\n *\n * @param client - GraphQL client\n * @param processingActivityIdPairs - [ProcessingActivityInput, processingActivityId] list\n * @param options - Options\n */\nasync function updateProcessingActivities(\n client: GraphQLClient,\n processingActivityIdPairs: [ProcessingActivityInput, string][],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n const { logger = NOOP_LOGGER } = options;\n const invalidProcessingActivityTitles = processingActivityIdPairs\n .filter(([, id]) => id === undefined)\n .map(([{ title }]) => title);\n if (invalidProcessingActivityTitles.length > 0) {\n throw new Error(\n `The following ${\n invalidProcessingActivityTitles.length\n } processing activities do not exist and thus can't be updated: \"${invalidProcessingActivityTitles.join(\n '\", \"',\n )}\"`,\n );\n }\n await makeGraphQLRequest(client, UPDATE_PROCESSING_ACTIVITIES, {\n variables: {\n input: {\n processingActivities: processingActivityIdPairs.map(\n ([\n { processingSubPurposes, dataSubCategories, saaSCategories, ...processingActivity },\n id,\n ]) => ({\n dataSubCategoryInputs: dataSubCategories?.map(({ category, name }) => ({\n category,\n name: name ?? '',\n })),\n processingPurposeSubCategoryInputs: processingSubPurposes?.map(({ purpose, name }) => ({\n purpose,\n name: name ?? 'Other',\n })),\n saaSCategoryTitles: saaSCategories,\n ...processingActivity,\n id,\n }),\n ),\n },\n },\n logger,\n });\n}\n\n/**\n * Sync the data inventory processing activities\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncProcessingActivities(\n client: GraphQLClient,\n inputs: ProcessingActivityInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n let encounteredError = false;\n\n // Fetch existing\n logger.info(`Syncing \"${inputs.length}\" processing activities...`);\n const existingProcessingActivities = await fetchAllProcessingActivities(client, { logger });\n\n // Look up by title\n const processingActivityByTitle: Record<string, Pick<ProcessingActivity, 'id' | 'title'>> = keyBy(\n existingProcessingActivities,\n 'title',\n );\n\n // Create new processingActivities\n const newProcessingActivities = inputs.filter((input) => !processingActivityByTitle[input.title]);\n if (newProcessingActivities.length > 0) {\n logger.info(`Creating \"${newProcessingActivities.length}\" new processing activities...`);\n }\n await mapSeries(newProcessingActivities, async (processingActivity) => {\n try {\n const newProcessingActivity = await createProcessingActivity(client, processingActivity, {\n logger,\n });\n processingActivityByTitle[newProcessingActivity.title] = newProcessingActivity;\n logger.info(`Successfully created processing activity \"${processingActivity.title}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to create processing activity \"${processingActivity.title}\"! - ${(err as Error).message}`,\n );\n }\n });\n\n // Update all processing activities\n try {\n logger.info(`Updating \"${inputs.length}\" processing activities!`);\n await updateProcessingActivities(\n client,\n inputs\n .map((input) => [input, processingActivityByTitle[input.title]?.id] as const)\n .filter((x): x is [ProcessingActivityInput, string] => !!x[1]),\n { logger },\n );\n logger.info(`Successfully synced \"${inputs.length}\" processingActivities!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to sync \"${inputs.length}\" processingActivities! - ${(err as Error).message}`,\n );\n }\n\n return !encounteredError;\n}\n","import { IsoCountryCode, IsoCountrySubdivisionCode } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllVendors, type Vendor } from './fetchAllVendors.js';\nimport { UPDATE_VENDORS, CREATE_VENDOR } from './gqls/vendor.js';\n\nexport interface VendorInput {\n /** Display title of the vendor */\n title: string;\n /** Description of the vendor */\n description?: string;\n /** URL to the data processing agreement */\n dataProcessingAgreementLink?: string;\n /** Name of the primary contact */\n contactName?: string;\n /** Phone number of the primary contact */\n contactPhone?: string;\n /** Physical address */\n address?: string;\n /** Headquarters country */\n headquarterCountry?: IsoCountryCode;\n /** Headquarters country subdivision */\n headquarterSubDivision?: IsoCountrySubdivisionCode;\n /** Vendor website URL */\n websiteUrl?: string;\n /** Title of the associated business entity */\n businessEntity?: string;\n /** Owner email addresses to assign */\n owners?: string[];\n /** Team names to assign */\n teams?: string[];\n /** Custom attribute values to assign */\n attributes?: {\n /** Attribute key name */\n key: string;\n /** Attribute values */\n values: string[];\n }[];\n}\n\n/**\n * Input to create a new vendor\n *\n * @param client - GraphQL client\n * @param vendor - Input\n * @returns Created vendor\n */\nexport async function createVendor(\n client: GraphQLClient,\n options: {\n /** Vendor to create */\n input: VendorInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<Vendor, 'id' | 'title'>> {\n const { input: vendor, logger = NOOP_LOGGER } = options;\n const input = {\n title: vendor.title,\n description: vendor.description,\n address: vendor.address,\n headquarterCountry: vendor.headquarterCountry,\n headquarterSubDivision: vendor.headquarterSubDivision,\n dataProcessingAgreementLink: vendor.dataProcessingAgreementLink,\n contactName: vendor.contactName,\n contactPhone: vendor.contactPhone,\n websiteUrl: vendor.websiteUrl,\n // TODO: https://transcend.height.app/T-31994 - add attributes, teams, owners\n };\n\n const { createVendor } = await makeGraphQLRequest<{\n /** Create vendor mutation */\n createVendor: {\n /** Created vendor */\n vendor: Vendor;\n };\n }>(client, CREATE_VENDOR, {\n variables: { input },\n logger,\n });\n return createVendor.vendor;\n}\n\n/**\n * Input to update vendors\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateVendors(\n client: GraphQLClient,\n options: {\n /** [VendorInput, vendorId] list */\n input: [VendorInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: vendors, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_VENDORS, {\n variables: {\n input: {\n vendors: vendors.map(([vendor, id]) => ({\n id,\n title: vendor.title,\n description: vendor.description,\n address: vendor.address,\n headquarterCountry: vendor.headquarterCountry,\n headquarterSubDivision: vendor.headquarterSubDivision,\n dataProcessingAgreementLink: vendor.dataProcessingAgreementLink,\n contactName: vendor.contactName,\n contactPhone: vendor.contactPhone,\n websiteUrl: vendor.websiteUrl,\n // TODO: https://transcend.height.app/T-31994 - add teams, owners\n attributes: vendor.attributes,\n })),\n },\n },\n logger,\n });\n}\n\n/**\n * Sync the data inventory vendors\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncVendors(\n client: GraphQLClient,\n inputs: VendorInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n // Fetch existing\n logger.info(`Syncing \"${inputs.length}\" vendors...`);\n\n let encounteredError = false;\n\n // Fetch existing\n const existingVendors = await fetchAllVendors(client, { logger });\n\n // Look up by title\n const vendorByTitle: { [k in string]: Pick<Vendor, 'id' | 'title'> } = keyBy(\n existingVendors,\n 'title',\n );\n\n // Create new vendors\n const newVendors = inputs.filter((input) => !vendorByTitle[input.title]);\n\n // Create new vendors\n await mapSeries(newVendors, async (vendor) => {\n try {\n const newVendor = await createVendor(client, { input: vendor, logger });\n vendorByTitle[newVendor.title] = newVendor;\n logger.info(`Successfully synced vendor \"${vendor.title}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync vendor \"${vendor.title}\"! - ${(err as Error).message}`);\n }\n });\n\n // Update all vendors\n try {\n logger.info(`Updating \"${inputs.length}\" vendors!`);\n await updateVendors(client, {\n input: inputs.map((input) => [input, vendorByTitle[input.title]!.id]),\n logger,\n });\n logger.info(`Successfully synced \"${inputs.length}\" vendors!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync \"${inputs.length}\" vendors ! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const PURPOSES: DocumentNode = parse(gql`\n query TranscendCliPurposes(\n $first: Int!\n $offset: Int!\n $filterBy: TrackingPurposeFiltersInput\n $input: TrackingPurposeInput!\n ) {\n purposes(first: $first, offset: $offset, filterBy: $filterBy, input: $input) {\n nodes {\n id\n name\n description\n defaultConsent\n trackingType\n configurable\n essential\n showInConsentManager\n isActive\n displayOrder\n optOutSignals\n deletedAt\n authLevel\n showInPrivacyCenter\n title\n }\n }\n }\n`);\n","import { UserPrivacySignalEnum } from '@transcend-io/airgap.js-types';\nimport { DefaultConsentOption, PreferenceStoreAuthLevel } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PURPOSES } from './gqls/purpose.js';\n\nexport interface Purpose {\n /** ID of purpose */\n id: string;\n /** Name of purpose */\n name: string;\n /** Description of purpose */\n description: string;\n /** Default consent status */\n defaultConsent: DefaultConsentOption;\n /** Slug of purpose */\n trackingType: string;\n /** Whether the purpose is configurable */\n configurable: boolean;\n /** Whether the purpose is essential */\n essential: boolean;\n /** Whether to show the purpose in the consent manager */\n showInConsentManager: boolean;\n /** Whether the purpose is active */\n isActive: boolean;\n /** Display order of the purpose */\n displayOrder: number;\n /** Opt-out signals for the purpose */\n optOutSignals: UserPrivacySignalEnum[];\n /** Whether the purpose is deleted */\n deletedAt?: string;\n /** Authorization level required for the purpose */\n authLevel: PreferenceStoreAuthLevel;\n /** Whether to show the purpose in the privacy center */\n showInPrivacyCenter: boolean;\n /** Title of the purpose */\n title: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all purposes in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All purposes in the organization\n */\nexport async function fetchAllPurposes(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** Whether to include deleted purposes */\n includeDeleted?: boolean;\n };\n } = {},\n): Promise<Purpose[]> {\n const { logger, filterBy: { includeDeleted = false } = {} } = options;\n const purposes: Purpose[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n purposes: { nodes },\n } = await makeGraphQLRequest<{\n /** Purposes */\n purposes: {\n /** List */\n nodes: Purpose[];\n };\n }>(client, PURPOSES, {\n logger,\n variables: { first: PAGE_SIZE, offset, input: { includeDeleted } },\n });\n purposes.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return purposes.sort((a, b) => a.trackingType.localeCompare(b.trackingType));\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const PREFERENCE_TOPICS: DocumentNode = parse(gql`\n query TranscendCliPreferenceTopics(\n $first: Int!\n $offset: Int!\n $filterBy: PreferenceTopicFilterInput\n ) {\n preferenceTopics(first: $first, offset: $offset, filterBy: $filterBy) {\n nodes {\n id\n slug\n type\n title {\n id\n defaultMessage\n }\n showInPrivacyCenter\n displayDescription {\n id\n defaultMessage\n }\n defaultConfiguration\n preferenceOptionValues {\n slug\n title {\n id\n defaultMessage\n }\n }\n purpose {\n trackingType\n }\n }\n }\n }\n`);\n","import { PreferenceTopicType } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PREFERENCE_TOPICS } from './gqls/preferenceTopic.js';\n\nexport interface PreferenceTopic {\n /** ID of preference topic */\n id: string;\n /** Slug of preference topic */\n slug: string;\n /** Title of topic */\n title: {\n /** ID */\n id: string;\n /** Default message */\n defaultMessage: string;\n };\n /** Whether to show in privacy center */\n showInPrivacyCenter: boolean;\n /** Description to display in privacy center */\n displayDescription: {\n /** ID */\n id: string;\n /** Default message */\n defaultMessage: string;\n };\n /** Type of preference topic */\n type: PreferenceTopicType;\n /** Default configuration */\n defaultConfiguration: string;\n /** Option values */\n preferenceOptionValues: {\n /** Slug of value */\n slug: string;\n /** Title of value */\n title: {\n /** ID */\n id: string;\n /** Default message */\n defaultMessage: string;\n };\n }[];\n /** Related purpose */\n purpose: {\n /** Slug */\n trackingType: string;\n };\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all preference topics in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All preference topics in the organization\n */\nexport async function fetchAllPreferenceTopics(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<PreferenceTopic[]> {\n const { logger } = options;\n const preferenceTopics: PreferenceTopic[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n preferenceTopics: { nodes },\n } = await makeGraphQLRequest<{\n /** Preference topics */\n preferenceTopics: {\n /** List */\n nodes: PreferenceTopic[];\n };\n }>(client, PREFERENCE_TOPICS, {\n logger,\n variables: { first: PAGE_SIZE, offset },\n });\n preferenceTopics.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return preferenceTopics.sort((a, b) =>\n `${a.slug}:${a.purpose.trackingType}`.localeCompare(`${b.slug}:${b.purpose.trackingType}`),\n );\n}\n","import type { Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\n\nimport { type PreferenceTopic, fetchAllPreferenceTopics } from './fetchAllPreferenceTopics.js';\nimport { type Purpose, fetchAllPurposes } from './fetchAllPurposes.js';\n\nexport interface PurposeWithPreferences extends Purpose {\n /** Topics */\n topics: PreferenceTopic[];\n}\n\n/**\n * Fetch all purposes and preferences\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns List of purposes with their preference topics\n */\nexport async function fetchAllPurposesAndPreferences(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<PurposeWithPreferences[]> {\n const [purposes, topics] = await Promise.all([\n fetchAllPurposes(client, options),\n fetchAllPreferenceTopics(client, options),\n ]);\n\n return purposes.map((purpose) => ({\n ...purpose,\n topics: topics.filter((topic) => topic.purpose.trackingType === purpose.trackingType),\n }));\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const CREATE_PREFERENCE_ACCESS_TOKENS: DocumentNode = parse(gql`\n mutation TranscendCliCreatePreferenceAccessTokens($input: CreatePrivacyCenterAccessTokensInput!) {\n createPrivacyCenterAccessTokens(input: $input) {\n nodes {\n token\n }\n }\n }\n`);\n","import type { SombraStandardScope } from '@transcend-io/privacy-types';\nimport { map, type Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\nimport { chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { CREATE_PREFERENCE_ACCESS_TOKENS } from './gqls/preferenceAccessTokens.js';\n\nexport interface PreferenceAccessTokenInput {\n /** Slug of data subject to authenticate as */\n subjectType: string;\n /** Scopes to grant */\n scopes: SombraStandardScope[];\n /** Expiration time in seconds */\n expiresIn?: number;\n /** Email address of user */\n email: string;\n /** Core identifier for the user */\n coreIdentifier?: string;\n}\n\nexport interface PreferenceAccessTokenInputWithIndex extends PreferenceAccessTokenInput {\n /** Index of the input record */\n index?: number;\n}\n\nconst MAX_BATCH_SIZE = 50;\n\n/**\n * Create preference access tokens for a single page of identifiers.\n *\n * @param client - GraphQL client\n * @param records - Inputs to sign\n * @param logger - Logger\n * @returns list of access tokens\n */\nasync function createPreferenceAccessTokensPage(\n client: GraphQLClient,\n records: PreferenceAccessTokenInput[],\n logger?: Logger,\n): Promise<string[]> {\n const {\n createPrivacyCenterAccessTokens: { nodes },\n } = await makeGraphQLRequest<{\n /** createPrivacyCenterAccessTokens mutation */\n createPrivacyCenterAccessTokens: {\n /** Nodes */\n nodes: {\n /** Token */\n token: string;\n }[];\n };\n }>(client, CREATE_PREFERENCE_ACCESS_TOKENS, {\n logger,\n variables: { input: { records } },\n });\n return nodes.map((node) => node.token);\n}\n\n/**\n * Create preference access tokens for the given identifiers.\n *\n * @see https://docs.transcend.io/docs/articles/preference-management/access-links\n * @param client - GraphQL client\n * @param options - Options\n * @returns list of access tokens/input identifiers\n */\nexport async function createPreferenceAccessTokens(\n client: GraphQLClient,\n options: {\n /** Records to create tokens for */\n records: PreferenceAccessTokenInputWithIndex[];\n /** Logger instance */\n logger?: Logger;\n /** Optional progress emitter */\n emitProgress?: (progress: number) => void;\n /** Number of concurrent requests to make (default: 10) */\n concurrency?: number;\n },\n): Promise<\n {\n /** Identifier for the record */\n input: PreferenceAccessTokenInputWithIndex;\n /** Access token */\n accessToken: string;\n }[]\n> {\n const { records, logger, emitProgress, concurrency = 10 } = options;\n\n let completed = 0;\n emitProgress?.(0);\n\n const results: {\n /** Identifier for the record */\n input: PreferenceAccessTokenInput;\n /** Access token */\n accessToken: string;\n }[] = [];\n\n await map(\n chunk(records, MAX_BATCH_SIZE),\n async (chunkedRecords) => {\n const tokens = await createPreferenceAccessTokensPage(\n client,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n chunkedRecords.map(({ index, ...rest }) => rest),\n logger,\n );\n const mappedResults = tokens.map((token, idx) => ({\n input: chunkedRecords[idx]!,\n accessToken: token,\n }));\n results.push(...mappedResults);\n completed += chunkedRecords.length;\n emitProgress?.(completed);\n },\n { concurrency },\n );\n\n return results;\n}\n","import { PreferenceQueryResponseItem } from '@transcend-io/privacy-types';\nimport * as t from 'io-ts';\n\n/**\n * New response codec for the query endpoint\n */\nexport const ConsentPreferenceResponse = t.intersection([\n t.type({\n nodes: t.array(PreferenceQueryResponseItem),\n }),\n t.partial({\n /** Cursor for next page (opaque) */\n cursor: t.string,\n }),\n]);\n\n/**\n * Type override\n */\nexport type ConsentPreferenceResponse = t.TypeOf<typeof ConsentPreferenceResponse>;\n\n/** Identifier filter (new shape) */\nexport type PreferenceIdentifier = {\n /** e.g., \"email\", \"phone\" */\n name: string;\n /** identifier value */\n value: string;\n};\n\n/** Filter shape for the new query endpoint */\nexport type PreferencesQueryFilter = {\n /** Identifiers to filter by */\n identifiers?: PreferenceIdentifier[];\n /** Consent collection time */\n timestampBefore?: string;\n /** Consent collection time */\n timestampAfter?: string;\n /** System updatedAt time */\n system?: {\n /** Updated before this time */\n updatedBefore?: string;\n /** Updated after this time */\n updatedAfter?: string;\n };\n};\n\n/** Which dimension we chunk on */\nexport type ChunkMode = 'timestamp' | 'updated';\n","import {\n PreferenceQueryResponseItem,\n PreferenceStoreIdentifier,\n PreferenceUpdateItem,\n} from '@transcend-io/privacy-types';\nimport * as t from 'io-ts';\n\nexport const PurposeRowMapping = t.type({\n /**\n * The slug or trackingType of the purpose to map to\n *\n * e.g. `Marketing`\n */\n purpose: t.string,\n /**\n * If the column maps to a preference instead of a purpose\n * this is the slug of the purpose.\n *\n * null value indicates that this column maps to the true/false\n * value of the purpose\n */\n preference: t.union([t.string, t.null]),\n /**\n * The mapping between each row value and purpose/preference value.\n *\n * e.g. for a boolean preference or purpose\n * {\n * 'true': true,\n * 'false': false,\n * '': true,\n * }\n *\n * or for a single or multi select preference\n * {\n * '': true,\n * 'value1': 'Value1',\n * 'value2': 'Value2',\n * }\n */\n valueMapping: t.record(t.string, t.union([t.string, t.boolean, t.null, t.undefined])),\n});\n\n/** Override type */\nexport type PurposeRowMapping = t.TypeOf<typeof PurposeRowMapping>;\n\n/**\n * Mapping of column name to purpose row mapping.\n * This is used to map each column in the CSV to the relevant purpose and preference definitions in\n * transcend.\n */\nexport const ColumnPurposeMap = t.record(t.string, PurposeRowMapping);\n\n/** Override type */\nexport type ColumnPurposeMap = t.TypeOf<typeof ColumnPurposeMap>;\n\nexport const IdentifierMetadataForPreference = t.type({\n /** The identifier name */\n name: t.string,\n /** Is unique on preference store */\n isUniqueOnPreferenceStore: t.boolean,\n});\n\n/** Override type */\nexport type IdentifierMetadataForPreference = t.TypeOf<typeof IdentifierMetadataForPreference>;\n\n/**\n * Mapping of identifier name to the column name in the CSV file.\n * This is used to map each identifier name to the column in the CSV file.\n */\nexport const ColumnIdentifierMap = t.record(t.string, IdentifierMetadataForPreference);\n\n/** Override type */\nexport type ColumnIdentifierMap = t.TypeOf<typeof ColumnIdentifierMap>;\n\n/** Mapping of a CSV column to a metadata key in the preference store. */\nexport const MetadataMapping = t.type({\n /** The metadata key name in the preference store */\n key: t.string,\n});\n\n/** Override type */\nexport type MetadataMapping = t.TypeOf<typeof MetadataMapping>;\n\n/** Record mapping CSV column names to metadata keys. */\nexport const ColumnMetadataMap = t.record(t.string, MetadataMapping);\n\n/** Override type */\nexport type ColumnMetadataMap = t.TypeOf<typeof ColumnMetadataMap>;\n\nexport const FileMetadataState = t.intersection([\n t.type({\n /**\n * Definition of how to map each column in the CSV to\n * the relevant purpose and preference definitions in transcend\n */\n columnToPurposeName: t.record(t.string, PurposeRowMapping),\n /** Last time the file was last parsed at */\n lastFetchedAt: t.string,\n /**\n * Mapping of userId to the rows in the file that need to be uploaded\n * These uploads are overwriting non-existent preferences and are safe\n */\n pendingSafeUpdates: t.record(t.string, t.record(t.string, t.string)),\n /**\n * Mapping of userId to the rows in the file that need to be uploaded\n * these records have conflicts with existing consent preferences\n */\n pendingConflictUpdates: t.record(\n t.string,\n t.type({\n record: PreferenceQueryResponseItem,\n row: t.record(t.string, t.string),\n }),\n ),\n /**\n * Mapping of userId to the rows in the file that can be skipped because\n * their preferences are already in the store\n */\n skippedUpdates: t.record(t.string, t.record(t.string, t.string)),\n }),\n t.partial({\n /** Determine which column name in file maps to consent record identifier to upload on */\n identifierColumn: t.string,\n /** Determine which column name in file maps to the timestamp */\n timestampColum: t.string,\n }),\n]);\n\n/** Override type */\nexport type FileMetadataState = t.TypeOf<typeof FileMetadataState>;\n\n/**\n * Schema-only state for a preference CSV file format.\n *\n * Unlike FileMetadataState this does NOT embed upload receipts — it only\n * describes how columns map to identifiers, purposes, timestamps, and metadata.\n */\nexport const FileFormatState = t.intersection([\n t.type({\n /** Maps each CSV column to its purpose/preference definition in Transcend */\n columnToPurposeName: ColumnPurposeMap,\n /** ISO 8601 timestamp of when this config was last generated or refreshed */\n lastFetchedAt: t.string,\n /** Maps each CSV column to the identifier it represents (e.g. email, userId) */\n columnToIdentifier: ColumnIdentifierMap,\n }),\n t.partial({\n /** CSV column whose values contain the consent timestamp */\n timestampColumn: t.string,\n /** Maps CSV columns to metadata keys stored alongside the preference record */\n columnToMetadata: ColumnMetadataMap,\n /** CSV columns that should be skipped during upload */\n columnsToIgnore: t.array(t.string),\n }),\n]);\n\n/** Override type */\nexport type FileFormatState = t.TypeOf<typeof FileFormatState>;\n\n/**\n * This is the type of the receipts that are stored in the file\n * that is used to track the state of the upload process.\n * It is used to resume the upload process from where it left off.\n * It is used to persist the state of the upload process across multiple runs.\n */\nexport const PreferenceUpdateMap = t.record(\n t.string,\n // This can either be true to indicate the record is pending\n // or it can be an object showing the object\n // We only return a fixed number of results to avoid\n // making the JSON file too large\n t.union([t.boolean, PreferenceUpdateItem]),\n);\n\n/** Override type */\nexport type PreferenceUpdateMap = t.TypeOf<typeof PreferenceUpdateMap>;\n\n/**\n * This is the type of the pending updates that are safe to run without\n * conflicts with existing consent preferences.\n *\n * Key is primaryKey of the record in the file.\n * The value is the row in the file that is safe to upload.\n */\nexport const PendingSafePreferenceUpdates = t.record(\n t.string,\n // This can either be true to indicate the record is safe\n // or it can be an object showing the object\n // We only return a fixed number of results to avoid\n // making the JSON file too large\n t.union([t.boolean, t.record(t.string, t.string)]),\n);\n\n/** Override type */\nexport type PendingSafePreferenceUpdates = t.TypeOf<typeof PendingSafePreferenceUpdates>;\n\n/**\n * These are the updates that failed to be uploaded to the API.\n */\nexport const FailingPreferenceUpdates = t.record(\n t.string,\n t.type({\n /** Time upload ran at */\n uploadedAt: t.string,\n /** Attempts to upload that resulted in an error */\n error: t.string,\n /** The update body */\n update: PreferenceUpdateItem,\n }),\n);\n\n/** Override type */\nexport type FailingPreferenceUpdates = t.TypeOf<typeof FailingPreferenceUpdates>;\n\n/**\n * This is the type of the pending updates that are in conflict with existing consent preferences.\n *\n * Key is primaryKey of the record in the file.\n * The value is the row in the file that is pending upload.\n */\nexport const PendingWithConflictPreferenceUpdates = t.record(\n t.string,\n // We always return the conflicts for investigation\n t.type({\n /** Record to be inserted to transcend v1/preferences API */\n record: PreferenceQueryResponseItem,\n /** The row in the file that is pending upload */\n row: t.record(t.string, t.string),\n }),\n);\n\n/** Override type */\nexport type PendingWithConflictPreferenceUpdates = t.TypeOf<\n typeof PendingWithConflictPreferenceUpdates\n>;\n\n/**\n * The set of preference updates that are skipped\n * Key is primaryKey and value is the row in the CSV\n * that is skipped.\n *\n * This is usually because the preferences are already in the store\n * or there are duplicate rows in the CSV file that are identical.\n */\nexport const SkippedPreferenceUpdates = t.record(t.string, t.record(t.string, t.string));\n\n/** Override type */\nexport type SkippedPreferenceUpdates = t.TypeOf<typeof SkippedPreferenceUpdates>;\n\n/** Persist this data between runs of the script */\nexport const PreferenceState = t.type({\n /**\n * Store a cache of previous files read in\n */\n fileMetadata: t.record(t.string, FileMetadataState),\n /**\n * The set of successful uploads to Transcend\n * Mapping from userId to the upload metadata\n */\n failingUpdates: t.record(\n t.string,\n t.type({\n /** Time upload ran at */\n uploadedAt: t.string,\n /** Attempts to upload that resulted in an error */\n error: t.string,\n /** The update body */\n update: PreferenceUpdateItem,\n }),\n ),\n /**\n * The set of pending uploads to Transcend\n * Mapping from userId to the upload metadata\n */\n pendingUpdates: t.record(t.string, PreferenceUpdateItem),\n});\n\n/** Override type */\nexport type PreferenceState = t.TypeOf<typeof PreferenceState>;\n\nexport const RequestUploadReceipts = t.type({\n /** ISO 8601 timestamp of when the receipt file was last written */\n lastFetchedAt: t.string,\n /** Updates that can be applied without conflicting with existing preferences */\n pendingSafeUpdates: PendingSafePreferenceUpdates,\n /** Updates that conflict with existing preference values and need review */\n pendingConflictUpdates: PendingWithConflictPreferenceUpdates,\n /** Rows skipped because their preferences already match the store */\n skippedUpdates: SkippedPreferenceUpdates,\n /** Updates that were attempted but failed with an API error */\n failingUpdates: FailingPreferenceUpdates,\n /** Updates still queued to be sent to the API */\n pendingUpdates: PreferenceUpdateMap,\n /** Updates that have been successfully written to the preference store */\n successfulUpdates: PreferenceUpdateMap,\n});\n\n/** Override type */\nexport type RequestUploadReceipts = t.TypeOf<typeof RequestUploadReceipts>;\n\nexport const DeletePreferenceRecordsInput = t.type({\n /** Array of consent preference records to delete */\n records: t.array(\n t.type({\n /** The anchor identifier to locate the consent record */\n anchorIdentifier: PreferenceStoreIdentifier,\n /** The ISO 8601 timestamp of when the deletion is requested */\n timestamp: t.string,\n }),\n ),\n});\n\n/** Override type */\nexport type DeletePreferenceRecordsInput = t.TypeOf<typeof DeletePreferenceRecordsInput>;\n\nexport const DeletePreferenceRecordsResponse = t.intersection([\n t.type({\n /** Array of results for each preference record deletion */\n records: t.array(\n t.intersection([\n t.type({\n /** Whether the deletion was successful */\n success: t.boolean,\n }),\n t.partial({\n /** An error message if the deletion failed */\n errorMessage: t.string,\n }),\n ]),\n ),\n /** The list of failed deletions with their respective errors */\n failures: t.array(\n t.type({\n /** The index of the failed update in the original request */\n index: t.number,\n /** The error message associated with the failure */\n error: t.string,\n }),\n ),\n }),\n t.partial({\n /** Any general errors that occurred during the operation */\n errors: t.array(t.string),\n }),\n]);\n\n/** Override type */\nexport type DeletePreferenceRecordsResponse = t.TypeOf<typeof DeletePreferenceRecordsResponse>;\n\n/** CLI CSV Row for deleting preference records */\nexport const DeletePreferenceRecordCliCsvRow = t.type({\n /** The name of the identifier type (e.g., email, userId) */\n name: t.string,\n /** The value of the identifier */\n value: t.string,\n});\n\n/** Override type */\nexport type DeletePreferenceRecordCliCsvRow = t.TypeOf<typeof DeletePreferenceRecordCliCsvRow>;\n","import type { ColumnMetadataMap } from './codecs.js';\n\n/**\n * Extract metadata values from a CSV row based on the column-to-metadata mapping.\n *\n * @param options - Options for extracting metadata\n * @returns Array of metadata key-value pairs for the preference store API\n */\nexport function getPreferenceMetadataFromRow({\n row,\n columnToMetadata,\n}: {\n /** The CSV row as a record of column name to value */\n row: Record<string, string>;\n /** Mapping from CSV column name to metadata key */\n columnToMetadata: ColumnMetadataMap;\n}): Array<{\n /** Metadata key name */ key: string;\n /** Metadata value from the CSV row */\n value: string;\n}> {\n return Object.entries(columnToMetadata)\n .map(([columnName, { key }]) => {\n const value = row[columnName];\n // Skip if no value in the row or empty string\n if (value === undefined || value === '') {\n return null;\n }\n return { key, value };\n })\n .filter(\n (\n x,\n ): x is {\n /** Metadata key name */ key: string;\n /** Metadata value from the CSV row */\n value: string;\n } => x !== null,\n );\n}\n","import type { PreferenceStoreIdentifier } from '@transcend-io/privacy-types';\n\nimport type { FileFormatState } from './codecs.js';\n\n/**\n * Extract preference store identifiers from a CSV row based on the column-to-identifier mapping.\n *\n * @param options - Options\n * @returns Array of identifiers for the preference store API\n */\nexport function getPreferenceIdentifiersFromRow({\n row,\n columnToIdentifier,\n}: {\n /** The current row from CSV file */\n row: Record<string, string>;\n /** The current file metadata state */\n columnToIdentifier: FileFormatState['columnToIdentifier'];\n}): PreferenceStoreIdentifier[] {\n const identifiers = Object.entries(columnToIdentifier)\n .filter(([col]) => !!row[col])\n .map(([col, identifierMapping]) => ({\n name: identifierMapping.name,\n value: row[col]!,\n }));\n return identifiers.sort(\n (a, b) =>\n (a.name === 'email' ? -1 : 0) - (b.name === 'email' ? -1 : 0) ||\n a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }),\n );\n}\n","import type { FileFormatState, IdentifierMetadataForPreference } from './codecs.js';\n\n/**\n * Helper function to get unique identifier name present in a row\n *\n * @param options - Options\n * @param options.row - The current row from CSV file\n * @param options.columnToIdentifier - The column to identifier mapping metadata\n * @returns The unique identifier names present in the row\n */\nexport function getUniquePreferenceIdentifierNamesFromRow({\n row,\n columnToIdentifier,\n}: {\n /** The current row from CSV file */\n row: Record<string, string>;\n /** The current file metadata state */\n columnToIdentifier: FileFormatState['columnToIdentifier'];\n}): (IdentifierMetadataForPreference & {\n /** Column name */\n columnName: string;\n /** Value of the identifier in the row */\n value: string;\n})[] {\n return Object.entries(columnToIdentifier)\n .sort(\n ([, a], [, b]) =>\n (a.name === 'email' ? -1 : 0) - (b.name === 'email' ? -1 : 0) ||\n a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }),\n )\n .filter(([col]) => row[col] && columnToIdentifier[col]!.isUniqueOnPreferenceStore)\n .map(([col, identifier]) => ({\n ...identifier,\n columnName: col,\n value: row[col]!,\n }));\n}\n","import { PreferenceStorePurposeResponse, PreferenceTopicType } from '@transcend-io/privacy-types';\nimport { apply } from '@transcend-io/type-utils';\nimport { splitCsvToList } from '@transcend-io/utils';\n\nimport { PurposeRowMapping } from './codecs.js';\nimport type { PreferenceTopic } from './fetchAllPreferenceTopics.js';\n\n/**\n * Parse an arbitrary object to the Transcend PUT /v1/preference update shape\n * by using a mapping of column names to purpose/preference slugs.\n *\n * `columnToPurposeName` looks like:\n * {\n * 'my_purpose': { purpose: 'Marketing', preference: null, valueMapping: { 'true': true, 'false': false } },\n * 'has_topic_1': { purpose: 'Marketing', preference: 'BooleanPreference1', valueMapping: { 'true': true, 'false': false } },\n * 'has_topic_2': { purpose: 'Marketing', preference: 'SingleSelectPreference', valueMapping: { 'Option 1': 'Value1', 'Option 2': 'Value2' } }\n * }\n *\n * `row` looks like:\n * {\n * 'my_purpose': 'true',\n * 'has_topic_1': 'true',\n * 'has_topic_2': 'Option 1'\n * }\n *\n * OMISSION RULE:\n * - If `valueMapping[row[columnName]]`\n * returns `undefined` or `null`, we **omit** that column entirely (do not set purpose enabled, do not push a preference).\n * - For MultiSelect, **each token** is treated independently: tokens that map to `undefined|null` are skipped;\n * if all tokens are skipped, nothing is pushed.\n * - We still validate **types** for mapped values (e.g., boolean must map to boolean, select must map to string, etc.).\n *\n * NOTE:\n * - Final shape must have `enabled` for every purpose touched (enforced by `apply` below). If you omit all top-level purpose mappings,\n * but emit preferences, this will throw at the end. This preserves the existing “enabled required” contract.\n *\n * @param options - Options\n * @returns The parsed row\n */\nexport function getPreferenceUpdatesFromRow({\n row,\n columnToPurposeName,\n purposeSlugs,\n preferenceTopics,\n}: {\n /** Row to parse */\n row: Record<string, string>;\n /** Mapping from column name to parser config */\n columnToPurposeName: Record<string, PurposeRowMapping>;\n /** The set of allowed purpose slugs */\n purposeSlugs: string[];\n /** The preference topics */\n preferenceTopics: PreferenceTopic[];\n}): {\n [k in string]: Omit<PreferenceStorePurposeResponse, 'purpose'>;\n} {\n // Create a result object to store the parsed preferences\n const result: {\n [k in string]: Partial<PreferenceStorePurposeResponse>;\n } = {};\n\n // Iterate over each column and map to the purpose or preference\n Object.entries(columnToPurposeName).forEach(\n ([columnName, { purpose, preference, valueMapping }]) => {\n // Ensure the purpose is valid\n if (!purposeSlugs.includes(purpose)) {\n throw new Error(`Invalid purpose slug: ${purpose}, expected: ${purposeSlugs.join(', ')}`);\n }\n\n // The raw value from the CSV row for this column\n const rawValue = row[columnName] ?? '';\n\n // Check if parsing a preference or just the top level purpose\n if (preference) {\n const preferenceTopic = preferenceTopics.find(\n (x) => x.slug === preference && x.purpose.trackingType === purpose,\n );\n if (!preferenceTopic) {\n const allowedTopics = preferenceTopics\n .filter((x) => x.purpose.trackingType === purpose)\n .map((x) => x.slug);\n throw new Error(\n `Invalid preference slug: ${preference} for purpose: ${purpose}. ` +\n `Allowed preference slugs for purpose are: ${allowedTopics.join(',')}`,\n );\n }\n\n // Ensure destination array\n if (!result[purpose]) {\n result[purpose] = {\n preferences: [],\n };\n }\n if (!result[purpose].preferences) {\n result[purpose].preferences = [];\n }\n\n // handle each type of preference\n switch (preferenceTopic.type) {\n case PreferenceTopicType.Boolean: {\n const mappedValue = valueMapping[rawValue];\n // Throw error on missing mapping\n if (mappedValue === undefined && rawValue !== '') {\n throw new Error(\n `No preference mapping found for value \"${rawValue}\" in column ` +\n `\"${columnName}\" (purpose=${purpose}, preference=${preference})`,\n );\n }\n\n // Purposefully missing mapping\n if (mappedValue === null || mappedValue === undefined) {\n return;\n }\n\n // Ensure boolean\n if (typeof mappedValue !== 'boolean') {\n throw new Error(\n `Invalid value for boolean preference: ${preference}, expected boolean, got: ${rawValue}`,\n );\n }\n result[purpose].preferences!.push({\n topic: preference,\n choice: { booleanValue: mappedValue },\n });\n break;\n }\n\n case PreferenceTopicType.Select: {\n const mappedValue = valueMapping[rawValue];\n // Throw error on missing mapping\n if (mappedValue === undefined && rawValue !== '') {\n throw new Error(\n `No preference mapping found for value \"${rawValue}\" in column ` +\n `\"${columnName}\" (purpose=${purpose}, preference=${preference})`,\n );\n }\n\n // Omit if null\n if (mappedValue === null || mappedValue === undefined) {\n return;\n }\n\n // Ensure string\n if (typeof mappedValue !== 'string') {\n throw new Error(\n `Invalid value for select preference: ${preference}, expected string, got: ${rawValue}`,\n );\n }\n const trimmed = mappedValue.trim() || null;\n\n if (\n trimmed &&\n !preferenceTopic.preferenceOptionValues.map(({ slug }) => slug).includes(trimmed)\n ) {\n throw new Error(\n `Invalid value for select preference: ${preference}, expected one of: ` +\n `${preferenceTopic.preferenceOptionValues\n .map(({ slug }) => slug)\n .join(', ')}, got: ${rawValue}`,\n );\n }\n\n result[purpose].preferences!.push({\n topic: preference,\n choice: { selectValue: trimmed },\n });\n break;\n }\n\n case PreferenceTopicType.MultiSelect: {\n if (typeof rawValue !== 'string') {\n throw new Error(\n `Invalid value for multi select preference: ${preference}, expected string, got: ${rawValue}`,\n );\n }\n\n // IMPORTANT: Do NOT rely on valueMapping[rawValue] for CSV.\n // Split and map per token with the new rule.\n const selectValues = splitCsvToList(rawValue)\n .map((token) => {\n const tokenMapped = valueMapping[token];\n // Throw error on missing mapping\n if (tokenMapped === undefined && rawValue !== '') {\n throw new Error(\n `No preference mapping found for multi select token \"${rawValue}\" in column ` +\n `\"${columnName}\" (purpose=${purpose}, preference=${preference})`,\n );\n }\n\n // Omit if null\n if (tokenMapped === null || tokenMapped === undefined) {\n return null;\n }\n\n // Ensure string\n if (typeof tokenMapped !== 'string') {\n throw new Error(\n `Invalid value for multi select preference: ${preference}, ` +\n `expected one of: ${preferenceTopic.preferenceOptionValues\n .map(({ slug }) => slug)\n .join(', ')}, got: ${token}`,\n );\n }\n return tokenMapped;\n })\n .filter((x): x is string => x !== null)\n .sort((a, b) => a.localeCompare(b));\n\n // Only push if at least one mapped token survived\n if (selectValues.length > 0) {\n result[purpose].preferences!.push({\n topic: preference,\n choice: { selectValues },\n });\n }\n break;\n }\n\n default:\n throw new Error(`Unknown preference type: ${preferenceTopic.type}`);\n }\n } else {\n // Top-level purpose (no preference)\n const mappedValue = valueMapping[rawValue];\n if (mappedValue === undefined && rawValue !== '') {\n throw new Error(\n `No preference mapping found for value \"${rawValue}\" in column ` +\n `\"${columnName}\" (purpose=${purpose}, preference=∅) ${JSON.stringify(row)}`,\n );\n }\n if (mappedValue === null) {\n return; // Omit if null\n }\n\n if (!result[purpose]) {\n // Top-level purpose: set enabled strictly from mapped boolean\n result[purpose] = { enabled: mappedValue === true };\n } else {\n // Preserve preferences; update enabled\n result[purpose].enabled = mappedValue === true;\n }\n }\n },\n );\n\n // Ensure that enabled is provided for any purpose that appears.\n // (This preserves the prior contract and existing tests.)\n return apply(result, (x, purposeName) => {\n if (typeof x.enabled !== 'boolean') {\n throw new Error(`No mapping provided for purpose.enabled=true/false value: ${purposeName}`);\n }\n return {\n ...x,\n enabled: x.enabled!,\n };\n });\n}\n","import {\n PreferenceQueryResponseItem,\n PreferenceStorePurposeResponse,\n PreferenceTopicType,\n} from '@transcend-io/privacy-types';\n\nimport type { PreferenceTopic } from './fetchAllPreferenceTopics.js';\n\n/**\n * Check if the pending set of updates are exactly the same as the current consent record.\n *\n * @param options - Options\n * @returns Whether the pending updates already exist in the preference store\n */\nexport function checkIfPendingPreferenceUpdatesAreNoOp({\n currentConsentRecord,\n pendingUpdates,\n preferenceTopics,\n}: {\n /** The current consent record */\n currentConsentRecord: PreferenceQueryResponseItem;\n /** The pending updates */\n pendingUpdates: {\n [purposeName in string]: Omit<PreferenceStorePurposeResponse, 'purpose'>;\n };\n /** The preference topic configurations */\n preferenceTopics: PreferenceTopic[];\n}): boolean {\n // Check each update\n return Object.entries(pendingUpdates).every(([purposeName, { preferences = [], enabled }]) => {\n // Ensure the purpose exists\n const currentPurpose = currentConsentRecord.purposes.find(\n (existingPurpose) => existingPurpose.purpose === purposeName,\n );\n\n // Ensure purpose.enabled is in sync\n // Also false if the purpose does not exist\n const enabledIsInSync = !!currentPurpose && currentPurpose.enabled === enabled;\n if (!enabledIsInSync) {\n return false;\n }\n\n // Compare the preferences are in sync\n return preferences.every(\n ({ topic, choice }) =>\n // ensure preferences exist on record\n currentPurpose.preferences &&\n currentPurpose.preferences.find((existingPreference) => {\n // find matching topic\n if (existingPreference.topic !== topic) {\n return false;\n }\n\n // Determine type of preference topic\n const preferenceTopic = preferenceTopics.find(\n (x) => x.slug === topic && x.purpose.trackingType === purposeName,\n );\n if (!preferenceTopic) {\n throw new Error(`Could not find preference topic for ${topic}`);\n }\n\n // Handle comparison based on type\n switch (preferenceTopic.type) {\n case PreferenceTopicType.Boolean:\n return existingPreference.choice.booleanValue === choice.booleanValue;\n case PreferenceTopicType.Select:\n return existingPreference.choice.selectValue === choice.selectValue;\n case PreferenceTopicType.MultiSelect:\n // eslint-disable-next-line no-case-declarations\n const sortedCurrentValues = (existingPreference.choice.selectValues || []).sort();\n // eslint-disable-next-line no-case-declarations\n const sortedNewValues = (choice.selectValues || []).sort();\n return (\n sortedCurrentValues.length === sortedNewValues.length &&\n sortedCurrentValues.every((x, i) => x === sortedNewValues[i])\n );\n default:\n throw new Error(`Unknown preference topic type: ${preferenceTopic.type}`);\n }\n }),\n );\n });\n}\n","import {\n PreferenceQueryResponseItem,\n PreferenceStorePurposeResponse,\n PreferenceTopicType,\n} from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\n\nimport type { PreferenceTopic } from './fetchAllPreferenceTopics.js';\n\n/**\n * Check if the pending set of updates will result in a change of\n * value to an existing purpose or preference in the preference store.\n *\n * @param options - Options\n * @returns True if conflict, false if no conflict and just adding new data for first time\n */\nexport function checkIfPendingPreferenceUpdatesCauseConflict({\n currentConsentRecord,\n pendingUpdates,\n preferenceTopics,\n logger,\n}: {\n /** The current consent record */\n currentConsentRecord: PreferenceQueryResponseItem;\n /** The pending updates */\n pendingUpdates: {\n [purposeName in string]: Omit<PreferenceStorePurposeResponse, 'purpose'>;\n };\n /** The preference topic configurations */\n preferenceTopics: PreferenceTopic[];\n /** Optional logger — when provided, conflicts are logged */\n logger?: Logger;\n}): boolean {\n // Check if any update has conflict\n return !!Object.entries(pendingUpdates).find(([purposeName, { preferences = [], enabled }]) => {\n // Ensure the purpose exists\n const currentPurpose = currentConsentRecord.purposes.find(\n (existingPurpose) => existingPurpose.purpose === purposeName,\n );\n\n // If no purpose exists, then it is not a conflict\n if (!currentPurpose) {\n logger?.warn(\n `No existing purpose found for ${purposeName} in consent record for ${currentConsentRecord.userId}.`,\n );\n return false;\n }\n\n // If purpose.enabled value is off, this is a conflict\n if (currentPurpose.enabled !== enabled) {\n logger?.warn(\n `Purpose ${purposeName} enabled value conflict for user ${currentConsentRecord.userId}. ` +\n `Pending Value: ${enabled}, Current Value: ${currentPurpose.enabled}`,\n );\n return true;\n }\n\n // Check if any preferences are out of sync\n return !!preferences.find(({ topic, choice }) => {\n // find matching topic\n const currentPreference = (currentPurpose.preferences || []).find(\n (existingPreference) => existingPreference.topic === topic,\n );\n\n // if no topic exists, no conflict\n if (!currentPreference) {\n logger?.warn(\n `No existing preference found for topic ${topic} in purpose ` +\n `${purposeName} for user ${currentConsentRecord.userId}.`,\n );\n return false;\n }\n\n // Determine type of preference topic\n const preferenceTopic = preferenceTopics.find(\n (x) => x.slug === topic && x.purpose.trackingType === purposeName,\n );\n if (!preferenceTopic) {\n throw new Error(`Could not find preference topic for ${topic}`);\n }\n\n // Handle comparison based on type\n let boolMatch: boolean;\n let selectMatch: boolean;\n switch (preferenceTopic.type) {\n case PreferenceTopicType.Boolean:\n boolMatch = currentPreference.choice.booleanValue !== choice.booleanValue;\n logger?.warn(\n `Preference topic ${topic} boolean value conflict for user ` +\n `${currentConsentRecord.userId}. Expected: ${choice.booleanValue}, ` +\n `Found: ${currentPreference.choice.booleanValue}`,\n );\n return boolMatch;\n case PreferenceTopicType.Select:\n selectMatch = currentPreference.choice.selectValue !== choice.selectValue;\n logger?.warn(\n `Preference topic ${topic} select value conflict for user ` +\n `${currentConsentRecord.userId}. Expected: ${choice.selectValue}, ` +\n `Found: ${currentPreference.choice.selectValue}`,\n );\n return selectMatch;\n case PreferenceTopicType.MultiSelect:\n // eslint-disable-next-line no-case-declarations\n const sortedCurrentValues = (currentPreference.choice.selectValues || []).sort();\n // eslint-disable-next-line no-case-declarations\n const sortedNewValues = (choice.selectValues || []).sort();\n selectMatch =\n sortedCurrentValues.length !== sortedNewValues.length ||\n !sortedCurrentValues.every((x, i) => x === sortedNewValues[i]);\n logger?.warn(\n `Preference topic ${topic} multi-select value conflict for user ` +\n `${currentConsentRecord.userId}. Expected: ${sortedNewValues.join(\n ', ',\n )}, Found: ${sortedCurrentValues.join(', ')}`,\n );\n return selectMatch;\n default:\n throw new Error(`Unknown preference topic type: ${preferenceTopic.type}`);\n }\n });\n });\n}\n","import { extractErrorMessage, sleepPromise, type Logger } from '@transcend-io/utils';\n\nimport { NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\n\n/**\n * Transient network / platform errors that merit a retry.\n * Keep this list short and specific to avoid masking real failures.\n */\nexport const RETRY_PREFERENCE_MSGS: string[] = [\n 'ENOTFOUND',\n 'ECONNRESET',\n 'ETIMEDOUT',\n '502 Bad Gateway',\n '504 Gateway Time-out',\n '429',\n 'Rate limit exceeded',\n 'Task timed out after',\n 'unknown request error',\n].map((s) => s.toLowerCase());\n\n/**\n * Options for retrying preference operations.\n */\nexport type RetryOptions = {\n logger?: Logger;\n /** Max attempts including the first try (default 12) */\n maxAttempts?: number;\n /** Initial backoff in ms (default 250) */\n baseDelayMs?: number;\n /** Optional custom predicate to decide if an error is retryable */\n isRetryable?: (err: unknown, message: string) => boolean;\n /** Optional hook to log on each retry */\n onRetry?: (attempt: number, err: unknown, message: string) => void;\n};\n\n/**\n * Run an async function with standardized retry behavior for preference operations.\n * Exponential backoff with jitter; only retries on known-transient messages.\n *\n * @param name - Name of the operation (for logging)\n * @param fn - Function to run\n * @param options - Retry options\n * @returns Result of the function\n */\nexport async function withPreferenceRetry<T>(\n name: string,\n fn: () => Promise<T>,\n {\n logger = NOOP_LOGGER,\n maxAttempts = 12,\n baseDelayMs = 250,\n isRetryable = (_err, msg) => RETRY_PREFERENCE_MSGS.some((m) => msg.toLowerCase().includes(m)),\n onRetry,\n }: RetryOptions,\n): Promise<T> {\n let attempt = 0;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n attempt += 1;\n try {\n return await fn();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (err: any) {\n const msg: string = extractErrorMessage(err);\n const willRetry = attempt < maxAttempts && isRetryable(err, msg);\n if (!willRetry) {\n throw new Error(`${name} failed after ${attempt} attempt(s): ${msg}`);\n }\n onRetry?.(attempt, err, msg);\n\n const backoff = baseDelayMs * 2 ** (attempt - 1);\n const jitter = Math.floor(Math.random() * baseDelayMs);\n const delay = backoff + jitter;\n logger.warn(`[retry] attempt ${attempt}/${maxAttempts - 1}; backing off ${delay}ms: ${msg}`);\n await sleepPromise(delay);\n }\n }\n}\n","import type { PreferenceQueryResponseItem } from '@transcend-io/privacy-types';\n\n/**\n * Transforms the output of the consent preferences query into a CSV-friendly format.\n *\n * @param input - The input object containing consent preferences data.\n * @param exportIdentifiersWithDelimiter - Delimiter to use when combining multiple identifier values.\n * @returns A record representing the transformed CSV output.\n */\nexport function transformPreferenceRecordToCsv(\n {\n identifiers = [],\n purposes = [],\n metadata = [],\n consentManagement = {},\n system = {\n decryptionStatus: 'DECRYPTED',\n },\n // keep other top-level fields as-is (e.g., partition, timestamp, metadataTimestamp)\n ...topLevel\n }: PreferenceQueryResponseItem,\n exportIdentifiersWithDelimiter: string,\n): Record<string, unknown> {\n // Start with: all other top-level fields + spread system and consentManagement\n const out: Record<string, unknown> = {\n ...topLevel,\n ...system,\n ...consentManagement,\n };\n\n // ── identifiers: each identifier.name -> CSV of values\n if (Array.isArray(identifiers)) {\n const byName = new Map<string, Set<string>>();\n for (const { name, value } of identifiers) {\n if (!byName.has(name)) byName.set(name, new Set());\n if (value) byName.get(name)!.add(value);\n }\n for (const [name, set] of byName.entries()) {\n out[name] = Array.from(set).join(exportIdentifiersWithDelimiter);\n }\n }\n\n // ── metadata: serialize as JSON\n if (Array.isArray(metadata)) {\n out.metadata = JSON.stringify(\n metadata.reduce(\n (acc, { key, value }) => {\n acc[key] = value;\n return acc;\n },\n {} as Record<string, string>,\n ),\n );\n }\n\n // ── purposes:\n // - purpose.slug column => true/false (enabled)\n // - for each preference: purpose.slug_preference.slug => bool | single | CSV (multi)\n if (Array.isArray(purposes)) {\n for (const { purpose, preferences, enabled } of purposes) {\n out[purpose] = Boolean(enabled);\n\n // nested preferences\n if (Array.isArray(preferences)) {\n for (const { topic, choice } of preferences) {\n const col = `${purpose}_${topic}`;\n\n let val: unknown = null;\n\n if (typeof choice.booleanValue === 'boolean') {\n val = choice.booleanValue;\n } else if (choice.selectValue) {\n val = choice.selectValue;\n } else if (Array.isArray(choice.selectValues)) {\n const vs = choice.selectValues.filter((v) => v.length > 0);\n val = vs.join(',');\n } else {\n // no pref value present -> null\n val = null;\n }\n\n out[col] = val;\n }\n }\n }\n }\n\n return out;\n}\n","import { FIVE_MIN_MS } from '@transcend-io/utils';\n\nimport type { ChunkMode, PreferencesQueryFilter } from './types.js';\n\n/**\n * Build chunk windows by splitting [lower, upperExclusive) into up to `maxChunks`\n * equal-sized ranges, with a minimum chunk span of 5 minutes. Boundaries are snapped\n * once at the start to the nearest 5-minute boundary for stability.\n *\n * Each returned window is already \"half-open\" for an *inclusive* backend:\n * we subtract 1ms from the exclusive end so adjacent chunks do not overlap.\n *\n * Example (timestamp mode): [10:00, 12:00) → { after=10:00:00.000Z, before=11:59:59.999Z }\n *\n * @param mode - 'timestamp' or 'updated'\n * @param lower - Lower bound (inclusive)\n * @param upperExclusive - Upper bound (exclusive)\n * @param maxChunks - Maximum number of chunks to create\n * @returns Array of chunked preference query filters\n */\nexport function buildConsentChunks(\n mode: ChunkMode,\n lower: Date,\n upperExclusive: Date,\n maxChunks = 5000,\n): Array<PreferencesQueryFilter> {\n const totalMs = Math.max(0, upperExclusive.getTime() - lower.getTime());\n if (totalMs === 0) return [];\n\n // Snap only the starting boundary to the nearest 5-minute boundary.\n // We avoid re-snapping every step to prevent cumulative drift.\n const seriesStart = new Date(Math.floor(lower.getTime() / FIVE_MIN_MS) * FIVE_MIN_MS);\n\n // Compute base chunk size (ceil to ensure ≤ maxChunks), enforced ≥ 5m.\n const rawChunkMs = Math.ceil(totalMs / Math.max(1, maxChunks));\n const chunkMs = Math.max(FIVE_MIN_MS, rawChunkMs);\n\n // Number of chunks needed to cover [seriesStart, upperExclusive)\n const count = Math.ceil((upperExclusive.getTime() - seriesStart.getTime()) / chunkMs);\n\n const chunks: PreferencesQueryFilter[] = [];\n\n for (let i = 0; i < count; i += 1) {\n const startMs = seriesStart.getTime() + i * chunkMs;\n const endExclusiveMs = Math.min(upperExclusive.getTime(), startMs + chunkMs);\n\n // Convert exclusive end to inclusive end for an inclusive backend: -1ms.\n const endInclusiveMs = endExclusiveMs - 1;\n\n // Guard: in degenerate cases (shouldn’t happen with the math above), clamp.\n const safeEndMs = Math.max(startMs, endInclusiveMs);\n\n const afterIso = new Date(startMs).toISOString();\n const beforeIso = new Date(safeEndMs).toISOString();\n\n if (mode === 'timestamp') {\n chunks.push({\n timestampAfter: afterIso,\n timestampBefore: beforeIso,\n });\n } else {\n chunks.push({\n system: {\n updatedAfter: afterIso,\n updatedBefore: beforeIso,\n },\n });\n }\n }\n\n return chunks;\n}\n","import type { ChunkMode, PreferencesQueryFilter } from './types.js';\n\n/**\n * Decide which dimension to chunk on: 'timestamp' if timestamps provided, otherwise 'updated'\n *\n * @param filterBy - Filter to examine\n * @returns Chosen chunk mode\n */\nexport function pickConsentChunkMode(filterBy: PreferencesQueryFilter): ChunkMode {\n const hasTimestamp = !!filterBy.timestampAfter || !!filterBy.timestampBefore;\n return hasTimestamp ? 'timestamp' : 'updated';\n}\n","import type { PreferenceQueryResponseItem } from '@transcend-io/privacy-types';\n\nimport type { ChunkMode } from './types.js';\n\n/**\n * Get the comparison instant for sorting based on the chosen dimension.\n *\n * @param mode - Chunking mode\n * @param item - Preference item\n * @returns date\n */\nexport function getComparisonTimeForRecord(\n mode: ChunkMode,\n item: PreferenceQueryResponseItem,\n): Date {\n if (mode === 'timestamp') {\n return new Date(item.timestamp);\n }\n // mode === 'updated'\n return item.system?.updatedAt ? new Date(item.system.updatedAt) : new Date();\n}\n","import type { PreferenceQueryResponseItem } from '@transcend-io/privacy-types';\nimport { decodeCodec } from '@transcend-io/type-utils';\nimport type { Logger } from '@transcend-io/utils';\nimport type { Got } from 'got';\n\nimport { ConsentPreferenceResponse, type PreferencesQueryFilter } from './types.js';\nimport { withPreferenceRetry } from './withPreferenceRetry.js';\n\n/**\n * Async generator over pages for a given filter\n *\n * @param sombra - Sombra Got instance\n * @param partition - Partition key\n * @param filter - Query filter\n * @param pageSize - Number of items per page\n * @param logger - Logger for retries\n * @yields Pages of PreferenceQueryResponseItem\n */\nexport async function* iterateConsentPages(\n sombra: Got,\n partition: string,\n filter: PreferencesQueryFilter,\n pageSize: number,\n logger: Logger,\n): AsyncGenerator<PreferenceQueryResponseItem[], void, void> {\n let cursor: string | undefined;\n\n while (true) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const body: any = { limit: pageSize };\n if (filter && Object.keys(filter).length) body.filter = filter;\n if (cursor) body.cursor = cursor;\n\n const resp = await withPreferenceRetry(\n 'Preference Query',\n () =>\n sombra\n .post(`v1/preferences/${partition}/query`, {\n json: body,\n })\n .json(),\n {\n logger,\n onRetry: (attempt, _error, message) => {\n logger.warn(`Retry attempt ${attempt} for iterateConsentPages due to error: ${message}`);\n },\n },\n );\n\n const { nodes, cursor: nextCursor } = decodeCodec(ConsentPreferenceResponse, resp);\n if (!nodes?.length) break;\n\n yield nodes;\n\n if (!nextCursor) break;\n cursor = nextCursor;\n }\n}\n","import { decodeCodec } from '@transcend-io/type-utils';\nimport type { Logger } from '@transcend-io/utils';\nimport type { Got } from 'got';\n\nimport { NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { ConsentPreferenceResponse, type PreferencesQueryFilter, type ChunkMode } from './types.js';\nimport { withPreferenceRetry } from './withPreferenceRetry.js';\n\n/**\n * Probe window: does it contain any records? Uses the given mode.\n *\n * @param sombra - Sombra\n * @param options - Options\n * @returns True if any records exist in the given window\n */\nexport async function consentWindowHasAny(\n sombra: Got,\n {\n partition,\n mode,\n baseFilter,\n afterISO,\n beforeISO,\n logger = NOOP_LOGGER,\n }: {\n /** Partition */\n partition: string;\n /** Chunking mode */\n mode: ChunkMode;\n /** Base filter */\n baseFilter: PreferencesQueryFilter;\n /** After ISO date */\n afterISO: string;\n /** Before ISO date */\n beforeISO: string;\n logger?: Logger;\n },\n): Promise<boolean> {\n const filter: PreferencesQueryFilter =\n mode === 'timestamp'\n ? {\n ...baseFilter,\n timestampAfter: afterISO,\n timestampBefore: beforeISO,\n system: baseFilter.system,\n }\n : {\n ...baseFilter,\n timestampAfter: undefined,\n timestampBefore: undefined,\n system: {\n ...baseFilter.system,\n updatedAfter: afterISO,\n updatedBefore: beforeISO,\n },\n };\n const resp = await withPreferenceRetry(\n 'Preference Query',\n () =>\n sombra\n .post(`v1/preferences/${partition}/query`, {\n json: { limit: 1, filter },\n })\n .json(),\n {\n logger,\n onRetry: (attempt, error, message) => {\n logger.warn(`Retry attempt ${attempt} for consentWindowHasAny due to error: ${message}`);\n },\n },\n );\n\n const { nodes } = decodeCodec(ConsentPreferenceResponse, resp);\n return Array.isArray(nodes) && nodes.length > 0;\n}\n","import type { PreferenceQueryResponseItem } from '@transcend-io/privacy-types';\nimport { startOfUtcDay, DAY_MS, type Logger } from '@transcend-io/utils';\n/* eslint-disable max-lines */\nimport type { Got } from 'got';\n\nimport { NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { getComparisonTimeForRecord } from './getComparisonTimeForRecord.js';\nimport { iterateConsentPages } from './iterateConsentPages.js';\nimport { pickConsentChunkMode } from './pickConsentChunkMode.js';\nimport { type ChunkMode, type PreferencesQueryFilter } from './types.js';\n\n/**\n * Get after/before bounds from filter for the given mode\n *\n * @param mode - Chunking mode\n * @param filterBy - Filter to examine\n * @returns after/before dates\n */\nexport function getBoundsFromConsentFilter(\n mode: ChunkMode,\n filterBy: PreferencesQueryFilter,\n): {\n /** After date */\n after?: Date;\n /** Before date */\n before?: Date;\n} {\n if (mode === 'timestamp') {\n return {\n after: filterBy.timestampAfter ? new Date(filterBy.timestampAfter) : undefined,\n before: filterBy.timestampBefore ? new Date(filterBy.timestampBefore) : undefined,\n };\n }\n const u = filterBy.system ?? {};\n return {\n after: u.updatedAfter ? new Date(u.updatedAfter) : undefined,\n before: u.updatedBefore ? new Date(u.updatedBefore) : undefined,\n };\n}\n\n/**\n * Merge base filter with a \"before\" bound (without mixing dimensions).\n *\n * @param mode - Chunking mode\n * @param base - Base filter to augment\n * @param beforeISO - ISO timestamp to apply as the exclusive *Before bound for the chosen dimension\n * @returns New filter with the appropriate *Before constraint applied\n */\nfunction withBeforeBound(\n mode: ChunkMode,\n base: PreferencesQueryFilter,\n beforeISO?: string,\n): PreferencesQueryFilter {\n if (mode === 'timestamp') {\n return {\n ...base,\n timestampBefore: beforeISO ?? base.timestampBefore,\n };\n }\n return {\n ...base,\n system: {\n ...base.system,\n ...(beforeISO ? { updatedBefore: beforeISO } : {}),\n },\n // ensure we don't mix dimensions\n timestampAfter: undefined,\n timestampBefore: undefined,\n };\n}\n\n/**\n * Fetch a single record (or null) with the given filter.\n *\n * @param sombra - Got instance configured for Sombra API\n * @param partition - Preference Store partition id\n * @param filter - Query filter to use (page size internally forced to 1)\n * @param logger - Logger\n * @returns The first record or null if none\n */\nasync function fetchOne(\n sombra: Got,\n partition: string,\n filter: PreferencesQueryFilter,\n logger: Logger,\n): Promise<PreferenceQueryResponseItem | null> {\n logger.info(`Single-record probe with filter: ${JSON.stringify(filter)}`);\n const it = iterateConsentPages(sombra, partition, filter, /* pageSize */ 1, logger);\n const res = await it.next();\n if (res.done || !res.value || res.value.length === 0) {\n logger.info('Probe result: no record');\n return null;\n }\n const item = res.value[0]!;\n logger.info(\n `Probe result: found record at ${getComparisonTimeForRecord(\n pickConsentChunkMode(filter),\n item,\n ).toISOString()}`,\n );\n return item;\n}\n\n/**\n * Robust earliest-day search (UTC):\n * 1) Anchor at the newest record (single-record probe).\n * 2) Exponential “jump back” using seeds (1d, 7d, 30d) then doubling (60d, 120d, 240d, …)\n * to cross into an empty region and establish a lower empty bound.\n * 3) **Exponential forward-from-empty**: gallop forward from the empty bound toward the last-found\n * to land close to the frontier quickly.\n * 4) Tighten with a short binary search on time using single-record probes.\n *\n * (Implementation note: preserves the public signature and docs while improving efficiency.)\n *\n * @param sombra - Sombra\n * @param opts - Options\n * @returns Earliest day with data (UTC start-of-day)\n */\nexport async function findEarliestDayWithData(\n sombra: Got,\n opts: {\n /** Partition */\n partition: string;\n /** Chunking mode */\n mode: ChunkMode;\n /** Base filter */\n baseFilter: PreferencesQueryFilter;\n /** Optional safety cap in days to avoid unbounded lookback (default ~10 years) */\n maxLookbackDays?: number;\n /** Logger */\n logger?: Logger;\n },\n): Promise<Date> {\n const { partition, mode, baseFilter, maxLookbackDays = 3650, logger = NOOP_LOGGER } = opts;\n\n // 1) Find newest record (anchors our backtracking).\n const newest = await fetchOne(sombra, partition, withBeforeBound(mode, baseFilter), logger);\n if (!newest) {\n logger.info('No records found; defaulting earliest day to today.');\n return startOfUtcDay(new Date());\n }\n const newestInstant = getComparisonTimeForRecord(mode, newest);\n logger.info(`Newest instant: ${newestInstant.toISOString()}`);\n\n // 2) Exponential jump back to find an empty region.\n const seedSteps = [1, 7, 30] as const; // days\n let stepDaysIdx = 0;\n let stepMs = seedSteps[0]! * DAY_MS;\n\n let lastFoundInstant = newestInstant; // last instant we *could* find a record before\n let emptyBeforeInstant: Date | null = null; // first bound that yielded no results\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const probeBound =\n stepDaysIdx < seedSteps.length\n ? new Date(newestInstant.getTime() - seedSteps[stepDaysIdx]! * DAY_MS)\n : new Date(newestInstant.getTime() - stepMs);\n\n // stop if we exceeded lookback cap\n const daysSince =\n (startOfUtcDay(new Date()).getTime() - startOfUtcDay(probeBound).getTime()) / DAY_MS;\n if (daysSince > maxLookbackDays) {\n logger.warn(\n `Exponential jump exceeded maxLookbackDays=${maxLookbackDays}. Using current bounds.`,\n );\n emptyBeforeInstant = probeBound;\n break;\n }\n\n logger.info(\n `Probing before=${probeBound.toISOString()} (jump step ${\n stepDaysIdx < seedSteps.length\n ? `${seedSteps[stepDaysIdx]!}d`\n : `${Math.round(stepMs / DAY_MS)}d`\n })…`,\n );\n\n const hit = await fetchOne(\n sombra,\n partition,\n withBeforeBound(mode, baseFilter, probeBound.toISOString()),\n logger,\n );\n\n if (hit) {\n lastFoundInstant = getComparisonTimeForRecord(mode, hit);\n logger.info(\n `Found older record at ${lastFoundInstant.toISOString()} — continue jumping back.`,\n );\n // advance step\n if (stepDaysIdx < seedSteps.length - 1) {\n stepDaysIdx += 1;\n stepMs = seedSteps[stepDaysIdx]! * DAY_MS;\n } else if (stepDaysIdx === seedSteps.length - 1) {\n stepDaysIdx += 1; // switch to doubling mode\n stepMs = seedSteps[seedSteps.length - 1]! * 2 * DAY_MS; // start at 60d\n } else {\n stepMs *= 2;\n }\n // eslint-disable-next-line no-continue\n continue;\n }\n\n // crossed into an empty zone — remember this bound\n emptyBeforeInstant = probeBound;\n logger.info(`No record before ${probeBound.toISOString()} — established empty lower bound.`);\n break;\n }\n\n // Guard: if for some reason empty bound wasn't set, synthesize one “just before” lastFound.\n if (!emptyBeforeInstant) {\n emptyBeforeInstant = new Date(lastFoundInstant.getTime() - DAY_MS);\n }\n\n // 3) Exponential forward-from-empty toward the found frontier.\n // This “gallop” reduces the span dramatically before binary search.\n // We keep moving the empty bound forward with exponentially growing steps\n // until we get a hit; then we shrink onto that hit instant.\n let lo = emptyBeforeInstant; // known EMPTY (no data before this bound)\n let hi = lastFoundInstant; // known FOUND (there is data before this instant)\n let fwdStep = Math.max(DAY_MS, Math.floor((hi.getTime() - lo.getTime()) / 64)); // start small-ish\n logger.info(\n `Exponential forward-from-empty start: empty=${lo.toISOString()} found=${hi.toISOString()} step=${Math.round(\n fwdStep / DAY_MS,\n )}d`,\n );\n\n // Do a few gallop iterations (bounded so we don't loop forever if distribution is dense)\n for (let i = 0; i < 8; i += 1) {\n const probe = new Date(lo.getTime() + fwdStep);\n if (probe.getTime() >= hi.getTime()) break;\n\n logger.info(`Forward gallop probe before=${probe.toISOString()}…`);\n const hit = await fetchOne(\n sombra,\n partition,\n withBeforeBound(mode, baseFilter, probe.toISOString()),\n logger,\n );\n\n if (hit) {\n // We crossed into data — tighten hi to the actual hit instant.\n hi = getComparisonTimeForRecord(mode, hit);\n logger.info(`Gallop hit at ${hi.toISOString()} — tightening found bound. Next step halves.`);\n fwdStep = Math.max(DAY_MS, Math.floor(fwdStep / 2));\n } else {\n // Still empty up to probe — advance lo and double the step.\n lo.setTime(probe.getTime());\n logger.info(`Gallop miss — advancing empty bound to ${lo.toISOString()}. Next step doubles.`);\n fwdStep = Math.min(hi.getTime() - lo.getTime(), fwdStep * 2);\n if (fwdStep < DAY_MS) fwdStep = DAY_MS;\n }\n\n if (hi.getTime() - lo.getTime() <= DAY_MS) break;\n }\n\n // 4) Finish with a short binary search between [lo (empty), hi (found)].\n while (hi.getTime() - lo.getTime() > DAY_MS) {\n const mid = new Date(lo.getTime() + Math.floor((hi.getTime() - lo.getTime()) / 2));\n logger.info(`Binary probe before=${mid.toISOString()}…`);\n\n const hit = await fetchOne(\n sombra,\n partition,\n withBeforeBound(mode, baseFilter, mid.toISOString()),\n logger,\n );\n\n if (hit) {\n const when = getComparisonTimeForRecord(mode, hit);\n logger.info(`Binary probe found record at ${when.toISOString()}.`);\n hi = when; // there is data before mid -> earliest could be even earlier\n } else {\n logger.info('Binary probe found no record.');\n lo = mid; // still empty -> move low up\n }\n }\n\n const earliestDay = startOfUtcDay(hi);\n logger.info(\n `Earliest day (UTC) resolved to ${earliestDay.toISOString()} (instant ≈ ${hi.toISOString()}).`,\n );\n return earliestDay;\n}\n\n/**\n * Find latest day with data using exponential growth forward from earliest (UTC day math).\n *\n * (Implementation note: per your request, we now fetch a single newest record to infer the latest day.)\n *\n * @param sombra - Sombra\n * @param opts - Options\n * @returns Latest day with data\n */\nexport async function findLatestDayWithData(\n sombra: Got,\n opts: {\n /** Partition */\n partition: string;\n /** Chunking mode */\n mode: ChunkMode;\n /** Base filter */\n baseFilter: PreferencesQueryFilter;\n /** Earliest date */\n earliest: Date; // inclusive day start\n /** Logger */\n logger?: Logger;\n },\n): Promise<Date> {\n const { partition, mode, baseFilter, logger = NOOP_LOGGER } = opts;\n\n logger.info('Latest-day discovery: probing newest record…');\n const latest = await fetchOne(sombra, partition, withBeforeBound(mode, baseFilter), logger);\n if (!latest) {\n logger.info('No records found at all; defaulting latest day to today.');\n return startOfUtcDay(new Date());\n }\n\n const when = getComparisonTimeForRecord(mode, latest);\n logger.info(`Newest record instant is ${when.toISOString()}.`);\n\n const latestDay = startOfUtcDay(when);\n logger.info(\n `Latest day (UTC) resolved to ${latestDay.toISOString()} from instant ${when.toISOString()}.`,\n );\n\n return latestDay;\n}\n/* eslint-enable max-lines */\n","import { PreferenceQueryResponseItem } from '@transcend-io/privacy-types';\nimport { decodeCodec } from '@transcend-io/type-utils';\nimport type { Logger } from '@transcend-io/utils';\nimport type { Got } from 'got';\n\nimport { NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { ConsentPreferenceResponse, type PreferencesQueryFilter } from './types.js';\nimport { withPreferenceRetry } from './withPreferenceRetry.js';\n\n/**\n * Fetch consent preferences for the managed consent database (new query endpoint)\n *\n * Uses POST /v1/preferences/{partition}/query with cursor pagination.\n *\n * If `onItems` is provided, this streams pages to the callback and does not\n * accumulate results in memory. If omitted, the function returns all items.\n *\n * @param sombra - Sombra instance (must include auth headers)\n * @param options - Query options\n * @returns All nodes (only when onItems is not provided)\n */\nexport async function fetchConsentPreferences(\n sombra: Got,\n {\n partition,\n filterBy = {},\n limit = 50,\n onItems,\n logger = NOOP_LOGGER,\n }: {\n /** Partition key to fetch (moved to URL path on new endpoint) */\n partition: string;\n /** Query filter (wrapped under \"filter\" in request body) */\n filterBy?: PreferencesQueryFilter;\n /** Number of users per page (1–50 per API spec) */\n limit?: number;\n /** Optional streaming sink; if provided, pages are not accumulated */\n onItems?: (items: PreferenceQueryResponseItem[]) => Promise<void> | void;\n logger?: Logger;\n },\n): Promise<PreferenceQueryResponseItem[]> {\n const collected: PreferenceQueryResponseItem[] = [];\n\n // Cursor-based pagination per new endpoint\n let cursor: string | undefined;\n\n // Build the filter payload, omitting empty filter\n const hasFilter =\n filterBy &&\n (Object.keys(filterBy).length > 0 ||\n (filterBy.system && Object.keys(filterBy.system).length > 0));\n\n // Enforce API max (defensive; backend also validates)\n const pageSize = Math.max(1, Math.min(50, limit ?? 50));\n\n // Keep fetching until no cursor is returned\n // (The API returns an opaque cursor string for the next page)\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const body: {\n /** Filter by user identifiers (new shape) */\n filter?: PreferencesQueryFilter;\n /** Cursor for pagination */\n cursor?: string;\n /** Number of records per page */\n limit: number;\n } = { limit: pageSize };\n\n if (hasFilter) {\n body.filter = filterBy;\n }\n if (cursor) {\n body.cursor = cursor;\n }\n\n const response = await withPreferenceRetry(\n 'Preference Query',\n () =>\n sombra\n .post(`v1/preferences/${partition}/query`, {\n json: body,\n })\n .json(),\n {\n logger,\n onRetry: (attempt, _error, message) => {\n logger.warn(\n `Retry attempt ${attempt} for fetchConsentPreferences due to error: ${message}`,\n );\n },\n },\n );\n\n const { nodes, cursor: nextCursor } = decodeCodec(ConsentPreferenceResponse, response);\n\n if (!nodes || nodes.length === 0) {\n break;\n }\n\n if (onItems) {\n await onItems(nodes);\n } else {\n collected.push(...nodes);\n }\n\n if (!nextCursor) {\n break;\n }\n cursor = nextCursor;\n }\n\n return onItems ? [] : collected;\n}\n","import { PreferenceQueryResponseItem } from '@transcend-io/privacy-types';\nimport { decodeCodec } from '@transcend-io/type-utils';\nimport { map, type Logger } from '@transcend-io/utils';\nimport type { Got } from 'got';\nimport { chunk } from 'lodash-es';\n\nimport { NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { ConsentPreferenceResponse } from './types.js';\nimport { withPreferenceRetry } from './withPreferenceRetry.js';\n\n/**\n * Grab the current consent preference values for a list of identifiers\n *\n * @param sombra - Backend to make API call to\n * @param options - Options\n * @returns Plaintext context information\n */\nexport async function getPreferencesForIdentifiers(\n sombra: Got,\n {\n identifiers,\n partitionKey,\n skipLogging = false,\n concurrency = 40,\n logger = NOOP_LOGGER,\n onProgress,\n }: {\n /** The list of identifiers to look up */\n identifiers: {\n /** The value of the identifier */\n value: string;\n }[];\n /** The partition key to look up */\n partitionKey: string;\n /** Whether to skip logging */\n skipLogging?: boolean;\n /** Concurrency for requests (default 40) */\n concurrency?: number;\n /** Logger */\n logger?: Logger;\n /** Optional progress callback (completed count, total identifiers) */\n onProgress?: (completed: number, total: number) => void;\n },\n): Promise<PreferenceQueryResponseItem[]> {\n const results: PreferenceQueryResponseItem[] = [];\n const groupedIdentifiers = chunk(identifiers, 100);\n\n const t0 = new Date().getTime();\n\n let total = 0;\n await map(\n groupedIdentifiers,\n async (group) => {\n const rawResult = await withPreferenceRetry(\n 'Preference Query',\n () =>\n sombra\n .post(`v1/preferences/${partitionKey}/query`, {\n json: {\n filter: { identifiers: group },\n limit: group.length,\n },\n })\n .json(),\n {\n logger,\n onRetry: (attempt, _err, msg) => {\n logger.warn(\n `[RETRY] group size=${group.length} partition=${partitionKey} attempt=${attempt}: ${msg}`,\n );\n },\n },\n );\n\n const result = decodeCodec(ConsentPreferenceResponse, rawResult);\n results.push(...result.nodes);\n total += group.length;\n onProgress?.(total, identifiers.length);\n },\n {\n concurrency,\n },\n );\n\n const t1 = new Date().getTime();\n const totalTime = t1 - t0;\n\n if (!skipLogging) {\n logger.info(`Completed download in \"${totalTime / 1000}\" seconds.`);\n }\n\n return results;\n}\n","import type { PreferenceQueryResponseItem } from '@transcend-io/privacy-types';\nimport { addDaysUtc, clampPageSize, map as pmap, type Logger } from '@transcend-io/utils';\nimport type { Got } from 'got';\n\nimport { NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { buildConsentChunks } from './buildConsentChunks.js';\nimport {\n findEarliestDayWithData,\n findLatestDayWithData,\n getBoundsFromConsentFilter,\n} from './discoverConsentWindow.js';\nimport { iterateConsentPages } from './iterateConsentPages.js';\nimport { pickConsentChunkMode } from './pickConsentChunkMode.js';\nimport { type PreferencesQueryFilter, type ChunkMode } from './types.js';\n\n/**\n * Merge baseFilter with a window filter, taking care not to mix timestamp/updated fields improperly.\n *\n * @param mode - The chunking mode\n * @param base - The base filter\n * @param window - The per-chunk window filter\n * @returns merged filter\n */\nfunction mergeFilter(\n mode: ChunkMode,\n base: PreferencesQueryFilter,\n window: PreferencesQueryFilter,\n): PreferencesQueryFilter {\n if (mode === 'timestamp') {\n return {\n ...base,\n timestampAfter: window.timestampAfter ?? base.timestampAfter,\n timestampBefore: window.timestampBefore ?? base.timestampBefore,\n // ensure we don't pass `system.*` when chunking by timestamp\n system: undefined,\n };\n }\n // mode === 'updated'\n return {\n ...base,\n system: {\n ...base.system,\n ...(window.system?.updatedAfter ? { updatedAfter: window.system.updatedAfter } : {}),\n ...(window.system?.updatedBefore ? { updatedBefore: window.system.updatedBefore } : {}),\n },\n // Ensure we don't mix dimensions\n timestampAfter: undefined,\n timestampBefore: undefined,\n };\n}\n\n/**\n * High-level chunked fetch with optional progress callback.\n *\n * If an `onItems` callback is provided, pages are streamed to the callback\n * as they are fetched (no accumulation in memory). If no callback is provided,\n * the function returns all items (legacy behavior).\n *\n * @param sombra - Got instance\n * @param options - Options\n * @returns preference items (only if onItems is not provided)\n */\nexport async function fetchConsentPreferencesChunked(\n sombra: Got,\n {\n partition,\n filterBy = {},\n limit = 50,\n windowConcurrency = 25,\n maxChunks = 5000,\n maxLookbackDays = 3650,\n onItems,\n logger = NOOP_LOGGER,\n onProgress,\n }: {\n /** Partition */\n partition: string;\n /** Filter by preferences */\n filterBy?: PreferencesQueryFilter;\n /** Limit number of results (page size) */\n limit?: number;\n /** Window concurrency */\n windowConcurrency?: number;\n /** Max chunks */\n maxChunks?: number; // up to N chunks; min 1 hour per chunk\n /** Max lookback days for discovering bounds */\n maxLookbackDays?: number;\n /** Optional streaming sink; if provided, items are not accumulated */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n onItems?: (items: PreferenceQueryResponseItem[]) => Promise<any> | any;\n /** Logger */\n logger?: Logger;\n /** Optional progress: completed chunks, total chunks, records fetched so far */\n onProgress?: (completed: number, total: number, fetched: number) => void;\n },\n): Promise<PreferenceQueryResponseItem[]> {\n const mode: ChunkMode = pickConsentChunkMode(filterBy);\n logger.info(\n `Fetching consent preferences in chunks by ${\n mode === 'timestamp' ? 'timestamp' : 'system.updatedAt'\n }...`,\n );\n\n // Resolve / discover bounds (UTC)\n let { after, before } = getBoundsFromConsentFilter(mode, filterBy);\n logger.info(\n `Initial bounds: after=${after?.toISOString() ?? 'undefined'} before=${\n before?.toISOString() ?? 'undefined'\n }`,\n );\n\n if (!after || !before) {\n if (!after) {\n logger.info(`Discovering earliest day with data for partition ${partition}...`);\n after = await findEarliestDayWithData(sombra, {\n partition,\n mode,\n baseFilter: filterBy,\n maxLookbackDays,\n logger,\n });\n logger.info(`Discovered earliest day with data: ${after.toISOString()}`);\n }\n if (!before) {\n logger.info(`Discovering latest day with data for partition ${partition}...`);\n const latestDay = await findLatestDayWithData(sombra, {\n partition,\n mode,\n baseFilter: filterBy,\n earliest: after,\n logger,\n });\n // Exclusive upper bound = latest day start + 1 day (UTC)\n before = addDaysUtc(latestDay, 1);\n logger.info(`Discovered latest day with data: ${latestDay.toISOString()}`);\n }\n }\n\n logger.info(`Final bounds (UTC): after=${after.toISOString()} before=${before.toISOString()}`);\n\n // Build up to `maxChunks` chunks, min 1 hour each\n const chunks = buildConsentChunks(mode, after, before, maxChunks);\n\n logger.info(\n `Fetching consent preferences from partition ${partition} in ${chunks.length} chunks...`,\n );\n\n let completed = 0; // finished chunks (out-of-order)\n let fetched = 0; // raw records counter\n\n const t0 = Date.now();\n const pageSize = clampPageSize(limit);\n\n // If we are streaming, do not accumulate everything in memory.\n const out: PreferenceQueryResponseItem[] = [];\n\n await pmap(\n chunks.map((windowFilter, idx) => ({ windowFilter, idx })),\n async ({ windowFilter }) => {\n const filter = mergeFilter(mode, filterBy, windowFilter);\n\n // Stream this chunk page-by-page\n for await (const page of iterateConsentPages(sombra, partition, filter, pageSize, logger)) {\n fetched += page.length;\n onProgress?.(completed, chunks.length, fetched);\n\n if (onItems) {\n await onItems(page);\n } else {\n out.push(...page);\n }\n }\n\n completed += 1;\n onProgress?.(completed, chunks.length, fetched);\n },\n { concurrency: Math.max(1, windowConcurrency) },\n );\n\n onProgress?.(completed, chunks.length, fetched);\n\n logger.info(\n `Fetched ${fetched} consent preference records from partition ${partition} in ${\n (Date.now() - t0) / 1000\n }s.`,\n );\n\n return onItems ? [] : out;\n}\n","import type { Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\n\nimport { fetchAllIdentifiers, type Identifier } from '../data-inventory/fetchAllIdentifiers.js';\nimport { fetchAllPreferenceTopics, type PreferenceTopic } from './fetchAllPreferenceTopics.js';\nimport { fetchAllPurposes, type Purpose } from './fetchAllPurposes.js';\n\nexport interface PreferenceUploadReferenceData {\n /** List of purposes in the organization */\n purposes: Purpose[];\n /** List of preference topics in the organization */\n preferenceTopics: PreferenceTopic[];\n /** List of identifiers in the organization */\n identifiers: Identifier[];\n}\n\n/**\n * Load all required reference data for an upload run.\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Reference data arrays\n */\nexport async function loadReferenceData(\n client: GraphQLClient,\n { logger }: { logger: Logger },\n): Promise<PreferenceUploadReferenceData> {\n const [purposes, preferenceTopics, identifiers] = await Promise.all([\n fetchAllPurposes(client, { logger }),\n fetchAllPreferenceTopics(client, { logger }),\n fetchAllIdentifiers(client, { logger }),\n ]);\n return { purposes, preferenceTopics, identifiers };\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const ATTRIBUTES = gql`\n query TranscendCliAttributes($first: Int!, $offset: Int!) {\n attributeKeys(first: $first, offset: $offset, useMaster: false) {\n nodes {\n id\n isCustom\n description\n enabledOn\n name\n type\n }\n }\n }\n`;\n\nexport const CREATE_ATTRIBUTE_VALUES = gql`\n mutation TranscendCliCreateAttributeValues($input: [CreateAttributeValuesInput!]!) {\n createAttributeValues(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const UPDATE_ATTRIBUTE_VALUES = gql`\n mutation TranscendCliUpdateAttributeValues($input: [UpdateAttributeValueInput!]!) {\n updateAttributeValues(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const DELETE_ATTRIBUTE_VALUE = gql`\n mutation TranscendCliDeleteAttributeValue($id: ID!) {\n deleteAttributeValue(id: $id) {\n clientMutationId\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const ATTRIBUTE_VALUES = gql`\n query TranscendCliAttributeValues($first: Int!, $offset: Int!, $attributeKeyId: ID!) {\n attributeValues(\n first: $first\n offset: $offset\n useMaster: false\n filterBy: { attributeKeys: [$attributeKeyId] }\n ) {\n nodes {\n id\n name\n description\n color\n }\n }\n }\n`;\n\nexport const CREATE_ATTRIBUTE = gql`\n mutation TranscendCliCreateAttribute(\n $name: String!\n $type: AttributeKeyType!\n $description: String\n $enabledOn: [AttributeSupportedResourceType!]\n ) {\n createAttributeKey(\n input: { name: $name, type: $type, description: $description, enabledOn: $enabledOn }\n ) {\n clientMutationId\n attributeKey {\n id\n }\n }\n }\n`;\n\nexport const UPDATE_ATTRIBUTE = gql`\n mutation TranscendCliCreateAttribute(\n $attributeKeyId: ID!\n $description: String\n $enabledOn: [AttributeSupportedResourceType!]\n ) {\n updateAttributeKey(\n input: { id: $attributeKeyId, description: $description, enabledOn: $enabledOn }\n ) {\n clientMutationId\n attributeKey {\n id\n }\n }\n }\n`;\n\nexport const SET_RESOURCE_ATTRIBUTES = gql`\n mutation TranscendCliSetResourceAttributes($input: SetResourceAttributesInput!) {\n setResourceAttributes(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { AttributeKeyType, AttributeSupportedResourceType } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { ATTRIBUTES, ATTRIBUTE_VALUES } from './gqls/attribute.js';\n\nexport interface AttributeValue {\n /** Attribute ID */\n id: string;\n /** Attribute name */\n name: string;\n /** Attribute description */\n description: string;\n /** Color of attribute value */\n color: string;\n}\n\nexport interface Attribute {\n /** ID of attribute */\n id: string;\n /** Name of attribute */\n name: string;\n /** if custom attribute */\n isCustom: boolean;\n /** Description */\n description: string;\n /** Type of attribute */\n type: AttributeKeyType;\n /** Values */\n values: AttributeValue[];\n /** The different fields that the attribute is enabled on */\n enabledOn: AttributeSupportedResourceType[];\n}\n\nconst PAGE_SIZE = 100;\n\n/**\n * Fetch all attribute values for an attribute key\n *\n * @param client - GraphQL client\n * @param attributeKeyId - Attribute keyID\n * @returns A map from apiKey title to Identifier\n */\nexport async function fetchAllAttributeValues(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy: {\n /** Attribute key ID */\n attributeKeyId: string;\n };\n },\n): Promise<AttributeValue[]> {\n const {\n logger,\n filterBy: { attributeKeyId },\n } = options;\n const attributeValues: AttributeValue[] = [];\n let offset = 0;\n\n // Paginate\n let shouldContinue = false;\n do {\n const {\n attributeValues: { nodes },\n } = await makeGraphQLRequest<{\n /** Query response */\n attributeValues: {\n /** List of matches */\n nodes: AttributeValue[];\n };\n }>(client, ATTRIBUTE_VALUES, {\n variables: { first: PAGE_SIZE, offset, attributeKeyId },\n logger,\n });\n attributeValues.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return attributeValues.sort((a, b) => a.name.localeCompare(b.name));\n}\n\nexport const SYNC_ATTRIBUTE_TYPES = [AttributeKeyType.MultiSelect, AttributeKeyType.SingleSelect];\n\n/**\n * Fetch all attributes in an organization\n *\n * @param client - GraphQL client\n * @returns A map from apiKey title to Identifier\n */\nexport async function fetchAllAttributes(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Attribute[]> {\n const { logger } = options;\n const attributes: Attribute[] = [];\n let offset = 0;\n\n // Paginate\n let shouldContinue = false;\n do {\n const {\n attributeKeys: { nodes },\n } = await makeGraphQLRequest<{\n /** Query response */\n attributeKeys: {\n /** List of matches */\n nodes: Attribute[];\n };\n }>(client, ATTRIBUTES, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n attributes.push(\n ...(await Promise.all(\n nodes.map(async (node) => ({\n ...node,\n values: SYNC_ATTRIBUTE_TYPES.includes(node.type)\n ? await fetchAllAttributeValues(client, {\n logger,\n filterBy: { attributeKeyId: node.id },\n })\n : [],\n })),\n )),\n );\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return attributes.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\nexport const MESSAGES = gql`\n query TranscendCliFetchMessage {\n translatedMessages {\n id\n defaultMessage\n description\n targetReactIntlId\n translations {\n locale\n value\n }\n }\n }\n`;\n\nexport const UPDATE_INTL_MESSAGES = gql`\n mutation TranscendCliUpdateIntlMessages($messages: [MessageInput!]!) {\n updateIntlMessages(input: { messages: $messages, skipPublish: true }) {\n clientMutationId\n }\n }\n`;\n","import type { LocaleValue } from '@transcend-io/internationalization';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { MESSAGES } from './gqls/message.js';\n\nexport interface Message {\n /** ID of message */\n id: string;\n /** Default message */\n defaultMessage: string;\n /** Description */\n description: string;\n /** React Intl ID */\n targetReactIntlId: string | null;\n /** Disabled locales */\n translations: {\n /** Locale */\n locale: LocaleValue;\n /** Value */\n value: string;\n }[];\n}\n\n/**\n * Fetch all messages in the organization\n *\n * @param client - GraphQL client\n * @returns All messages in the organization\n */\nexport async function fetchAllMessages(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Message[]> {\n const { logger } = options;\n const { translatedMessages } = await makeGraphQLRequest<{\n /** Messages */\n translatedMessages: Message[];\n }>(client, MESSAGES, { logger });\n return translatedMessages;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const TEAMS = gql`\n query TranscendCliTeams($first: Int!, $offset: Int!, $input: TeamFiltersInput) {\n teams(\n first: $first\n offset: $offset\n filterBy: $input\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n description\n ssoDepartment\n ssoGroup\n ssoTitle\n users {\n id\n email\n name\n }\n scopes {\n id\n name\n title\n }\n }\n }\n }\n`;\n\nexport const CREATE_TEAM = gql`\n mutation TranscendCliCreateTeam($input: TeamInput!) {\n createTeam(input: $input) {\n team {\n id\n name\n }\n }\n }\n`;\n\nexport const UPDATE_TEAM = gql`\n mutation TranscendCliUpdateTeam($input: UpdateTeamInput!) {\n updateTeam(input: $input) {\n team {\n id\n name\n }\n }\n }\n`;\n","import { ScopeName } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { TEAMS } from './gqls/team.js';\n\nexport interface Team {\n /** ID of team */\n id: string;\n /** Name of team */\n name: string;\n /** Description of team */\n description: string;\n /** SSO department for automated provisioning */\n ssoDepartment?: string;\n /** SSO group name for automated provisioning */\n ssoGroup?: string;\n /** SSO title mapping for automated provisioning */\n ssoTitle?: string;\n /** List of users on the team */\n users: {\n /** ID of user */\n id: string;\n /** Email of user */\n email: string;\n /** Name of user */\n name: string;\n }[];\n /** List of scopes on the team */\n scopes: {\n /** ID of scope */\n id: string;\n /** Name of scope */\n name: ScopeName;\n /** Title of scope */\n title: string;\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all teams in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All teams in the organization\n */\nexport async function fetchAllTeams(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Team[]> {\n const { logger } = options;\n const teams: Team[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n teams: { nodes },\n } = await makeGraphQLRequest<{\n /** Teams */\n teams: {\n /** List */\n nodes: Team[];\n };\n }>(client, TEAMS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n teams.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return teams.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const USERS = gql`\n query TranscendCliUsers($first: Int!, $offset: Int!, $input: UserFiltersInput) {\n users(\n first: $first\n offset: $offset\n filterBy: $input\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n email\n }\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { USERS } from './gqls/user.js';\n\nexport interface User {\n /** ID of user */\n id: string;\n /** Name of user */\n name: string;\n /** Email of user */\n email: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all users in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All users in the organization\n */\nexport async function fetchAllUsers(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<User[]> {\n const { logger } = options;\n const users: User[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n users: { nodes },\n } = await makeGraphQLRequest<{\n /** Users */\n users: {\n /** List */\n nodes: User[];\n };\n }>(client, USERS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n users.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return users.sort((a, b) => a.email.localeCompare(b.email));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const API_KEYS = gql`\n query TranscendCliApiKeys($first: Int!, $offset: Int!, $titles: [String!]) {\n apiKeys(\n first: $first\n offset: $offset\n filterBy: { titles: $titles }\n useMaster: false\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n ) {\n nodes {\n id\n title\n }\n }\n }\n`;\n\nexport const CREATE_API_KEY = gql`\n mutation TranscendCliCreateApiKey($input: ApiKeyInput!) {\n createApiKey(input: $input) {\n apiKey {\n id\n apiKey\n title\n }\n }\n }\n`;\n\nexport const DELETE_API_KEY = gql`\n mutation TranscendCliDeleteApiKey($id: ID!) {\n deleteApiKey(id: $id) {\n clientMutationId\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy, uniq, difference } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { API_KEYS } from './gqls/apiKey.js';\n\nexport interface ApiKey {\n /** ID of API key */\n id: string;\n /** Title of API key */\n title: string;\n}\n\nexport interface FetchApiKeysInput {\n /** API key definitions */\n 'api-keys'?: {\n /** Title of API key */\n title: string;\n }[];\n /** Data silo definitions that may reference API keys */\n 'data-silos'?: {\n /** Title of the API key to use */\n 'api-key-title'?: string;\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\nconst ADMIN_LINK = 'https://app.transcend.io/infrastructure/api-keys';\n\n/**\n * Fetch all API keys in an organization\n *\n * @param client - Client\n * @param options - Options\n * @returns API keys\n */\nexport async function fetchAllApiKeys(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** Filter on titles */\n titles?: string[];\n };\n } = {},\n): Promise<ApiKey[]> {\n const { logger = NOOP_LOGGER, filterBy: { titles } = {} } = options;\n const apiKeys: ApiKey[] = [];\n let offset = 0;\n\n // Paginate\n let shouldContinue = false;\n do {\n const {\n apiKeys: { nodes },\n } = await makeGraphQLRequest<{\n /** API keys */\n apiKeys: {\n /** List */\n nodes: ApiKey[];\n };\n }>(client, API_KEYS, {\n variables: { first: PAGE_SIZE, offset, titles },\n logger,\n });\n apiKeys.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n return apiKeys.sort((a, b) => a.title.localeCompare(b.title));\n}\n\n/**\n * Fetch all apiKeys and if any are found in the config that are\n * missing, create those apiKeys.\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns A map from apiKey title to Identifier\n */\nexport async function fetchApiKeys(\n client: GraphQLClient,\n options: {\n /** API key input configuration */\n apiKeyInputs?: FetchApiKeysInput;\n /** When true, fetch all API keys */\n fetchAll?: boolean;\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<{ [k in string]: ApiKey }> {\n const {\n apiKeyInputs: { 'api-keys': apiKeyDefs = [], 'data-silos': dataSilos = [] } = {},\n fetchAll = false,\n logger = NOOP_LOGGER,\n } = options;\n logger.info(`Fetching ${fetchAll ? 'all' : apiKeyDefs.length} API keys...`);\n const titles = apiKeyDefs.map(({ title }) => title);\n const expectedApiKeyTitles = uniq(\n dataSilos.map((silo) => silo['api-key-title']).filter((x): x is string => !!x),\n );\n const allTitlesExpected = [...expectedApiKeyTitles, ...titles];\n const apiKeys = await fetchAllApiKeys(client, {\n logger,\n filterBy: {\n titles: fetchAll ? undefined : [...expectedApiKeyTitles, ...titles],\n },\n });\n\n // Create a map\n const apiKeysByTitle = keyBy(apiKeys, 'title');\n\n // Determine expected set of apiKeys expected\n const missingApiKeys = difference(\n allTitlesExpected,\n apiKeys.map(({ title }) => title),\n );\n\n // If there are missing apiKeys, throw an error\n if (missingApiKeys.length > 0) {\n logger.error(\n `Failed to find API keys \"${missingApiKeys.join(\n '\", \"',\n )}\"! Make sure these API keys are created at: ${ADMIN_LINK}`,\n );\n process.exit(1);\n }\n return apiKeysByTitle;\n}\n","import { IsoCountrySubdivisionCode, IsoCountryCode } from '@transcend-io/privacy-types';\n\nexport interface RegionInput {\n /** The country */\n country?: IsoCountryCode;\n /** The country subdivision */\n countrySubDivision?: IsoCountrySubdivisionCode;\n}\n\n// Country subdivision is nullable in DB\nexport interface Region {\n /** Country */\n country: IsoCountryCode;\n /** Sub division (may be null in DB) */\n countrySubDivision?: IsoCountrySubdivisionCode | null;\n}\n\n/**\n * Format regions list to remove null country subdivisions\n *\n * @param vals - Regions\n * @returns formatted regions\n */\nexport function formatRegions(vals: Region[]): RegionInput[] {\n return vals.map(({ country, countrySubDivision }) => ({\n country,\n ...(countrySubDivision ? { countrySubDivision } : {}),\n }));\n}\n","import { gql } from 'graphql-request';\n\nexport const DETERMINE_LOGIN_METHOD = gql`\n mutation TranscendCliDetermineLoginMethod($email: String!) {\n determineLoginMethod(input: { email: $email }) {\n loginMethod {\n email\n sombraPublicKey\n }\n }\n }\n`;\n\nexport const LOGIN = gql`\n mutation TranscendCliLogin($email: String!, $password: String!, $publicKey: String!) {\n login(input: { email: $email, password: $password }, publicKey: $publicKey) {\n user {\n roles {\n id\n organization {\n name\n id\n uri\n parentOrganizationId\n }\n }\n }\n }\n }\n`;\n\nexport const ASSUME_ROLE = gql`\n mutation TranscendCliAssumeRole($id: ID!, $publicKey: String!) {\n assumeRole(id: $id, publicKey: $publicKey) {\n clientMutationId\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { DETERMINE_LOGIN_METHOD, ASSUME_ROLE, LOGIN } from './gqls/auth.js';\n\nexport interface OrganizationPreview {\n /** Name of organization */\n name: string;\n /** Id of organization */\n id: string;\n /** uri of organization */\n uri: string;\n /** ID of parent organization */\n parentOrganizationId?: string;\n}\n\nexport interface UserRole {\n /** ID of role */\n id: string;\n /** Related organization */\n organization: OrganizationPreview;\n}\n\n/**\n * Log in as a user\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Cookie and roles\n */\nexport async function loginUser(\n client: GraphQLClient,\n options: {\n /** Email of user */\n email: string;\n /** Password of user */\n password: string;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<{\n /** Cookie to be used to make subsequent requests */\n loginCookie: string;\n /** Roles of the user */\n roles: UserRole[];\n}> {\n const { email, password, logger } = options;\n\n const {\n determineLoginMethod: { loginMethod },\n } = await makeGraphQLRequest<{\n /** Determine login method */\n determineLoginMethod: {\n /** Login method info */\n loginMethod: {\n /** Email being logged in */\n email: string;\n /** Sombra public key */\n sombraPublicKey: string;\n };\n };\n }>(client, DETERMINE_LOGIN_METHOD, {\n variables: { email },\n logger,\n });\n\n const res = await client.rawRequest<{\n /** Login */\n login: {\n /** User */\n user: {\n /** Roles of user */\n roles: UserRole[];\n };\n };\n }>(LOGIN, {\n email,\n password,\n publicKey: loginMethod.sombraPublicKey,\n });\n const {\n login: { user },\n } = res.data;\n\n // Get login cookie from response\n const loginCookie = res.headers.get('set-cookie');\n if (!loginCookie || !loginCookie.includes('laravel')) {\n throw new Error('Failed to get login cookie in response');\n }\n\n return {\n roles: user.roles,\n loginCookie,\n };\n}\n\n/**\n * Assume role for user into another organization\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function assumeRole(\n client: GraphQLClient,\n options: {\n /** Email of user */\n email: string;\n /** Role of user assuming into */\n roleId: string;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { email, roleId, logger } = options;\n\n const {\n determineLoginMethod: { loginMethod },\n } = await makeGraphQLRequest<{\n /** Determine login method */\n determineLoginMethod: {\n /** Login method info */\n loginMethod: {\n /** Email being logged in */\n email: string;\n /** Sombra public key */\n sombraPublicKey: string;\n };\n };\n }>(client, DETERMINE_LOGIN_METHOD, {\n variables: { email, userId: roleId },\n logger,\n });\n\n await client.rawRequest<{\n /** Assume role */\n assumeRole: {\n /** Mutation ID */\n clientMutationId: string;\n };\n }>(ASSUME_ROLE, {\n id: roleId,\n publicKey: loginMethod.sombraPublicKey,\n });\n}\n","import { ScopeName } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { CREATE_API_KEY, DELETE_API_KEY } from './gqls/apiKey.js';\n\nexport interface CreatedApiKey {\n /** ID of API key */\n id: string;\n /** Actual API key */\n apiKey: string;\n /** Title of the API key */\n title: string;\n}\n\n/**\n * Create an API key\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns The API key\n */\nexport async function createApiKey(\n client: GraphQLClient,\n options: {\n /** Input for creating an API key */\n input: {\n /** Title of API key */\n title: string;\n /** Scopes for API key */\n scopes: ScopeName[];\n };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<CreatedApiKey> {\n const {\n input: { title, scopes },\n logger,\n } = options;\n const {\n createApiKey: { apiKey },\n } = await makeGraphQLRequest<{\n /** Create API key */\n createApiKey: {\n /** API key */\n apiKey: CreatedApiKey;\n };\n }>(client, CREATE_API_KEY, { variables: { input: { title, scopes } }, logger });\n\n return apiKey;\n}\n\n/**\n * Delete an API key\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function deleteApiKey(\n client: GraphQLClient,\n options: {\n /** API key ID to delete */\n id: string;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { id, logger } = options;\n await makeGraphQLRequest(client, DELETE_API_KEY, { variables: { id }, logger });\n}\n","import { AttributeSupportedResourceType } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { SET_RESOURCE_ATTRIBUTES } from './gqls/attribute.js';\n\ninterface SetResourceAttributesInput {\n /** ID of resource */\n resourceId: string;\n /** Type of resource */\n resourceType: AttributeSupportedResourceType;\n /** Attribute key ID */\n attributeKeyId: string;\n /** Attribute values by ID */\n attributeValueIds?: string[];\n /** Attribute values by name */\n attributeValueNames?: string[];\n}\n\n/**\n * Set attribute values on a particular resource\n *\n * @param client - GraphQL client\n * @param input - Input\n */\nexport async function setResourceAttributes(\n client: GraphQLClient,\n input: SetResourceAttributesInput,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n const { logger } = options;\n await makeGraphQLRequest(client, SET_RESOURCE_ATTRIBUTES, {\n variables: { input },\n logger,\n });\n}\n","import { AttributeKeyType, AttributeSupportedResourceType } from '@transcend-io/privacy-types';\nimport { map, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy, difference, groupBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { type Attribute } from './fetchAllAttributes.js';\nimport {\n CREATE_ATTRIBUTE,\n CREATE_ATTRIBUTE_VALUES,\n DELETE_ATTRIBUTE_VALUE,\n UPDATE_ATTRIBUTE,\n UPDATE_ATTRIBUTE_VALUES,\n} from './gqls/attribute.js';\n\nexport interface AttributeValueInput {\n /** Name of attribute value */\n name: string;\n /** Description */\n description?: string;\n /** Color */\n color?: string;\n}\n\nexport interface AttributeInput {\n /** Name of attribute */\n name: string;\n /** Type of attribute */\n type: AttributeKeyType;\n /** Description of attribute */\n description?: string;\n /** Resource types that the attribute is enabled on */\n resources?: AttributeSupportedResourceType[];\n /** Values of attribute */\n values?: AttributeValueInput[];\n}\n\n/**\n * Sync attribute\n *\n * @param client - GraphQL client\n * @param attribute - The attribute input\n * @param options - Options\n */\nexport async function syncAttribute(\n client: GraphQLClient,\n attribute: AttributeInput,\n {\n existingAttribute,\n deleteExtraAttributeValues,\n logger = NOOP_LOGGER,\n }: {\n /** The existing attribute configuration if it exists */\n existingAttribute?: Attribute;\n /** When true, delete extra attributes not specified in the list of values */\n deleteExtraAttributeValues?: boolean;\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n // attribute key input\n const input = {\n name: attribute.name,\n enabledOn: attribute.resources,\n };\n\n // create or update attribute key\n let attributeKeyId: string;\n if (!existingAttribute) {\n const {\n createAttributeKey: { attributeKey },\n } = await makeGraphQLRequest<{\n /** Create attribute key response */\n createAttributeKey: {\n /** Attribute key */\n attributeKey: {\n /** ID */\n id: string;\n };\n };\n }>(client, CREATE_ATTRIBUTE, {\n variables: {\n type: attribute.type,\n description: attribute.description,\n ...input,\n },\n logger,\n });\n attributeKeyId = attributeKey.id;\n } else {\n await makeGraphQLRequest(client, UPDATE_ATTRIBUTE, {\n variables: {\n attributeKeyId: existingAttribute.id,\n description: existingAttribute.isCustom ? attribute.description : undefined,\n ...input,\n },\n logger,\n });\n attributeKeyId = existingAttribute.id;\n }\n\n // upsert attribute values\n const existingAttributeMap = keyBy(existingAttribute?.values || [], 'name');\n const { existingValues = [], newValues = [] } = groupBy(attribute.values || [], (field) =>\n existingAttributeMap[field.name] ? 'existingValues' : 'newValues',\n );\n const removedValues = difference(\n (existingAttribute?.values || []).map(({ name }) => name),\n (attribute.values || []).map(({ name }) => name),\n );\n\n // Create new attribute values\n if (newValues.length > 0) {\n await makeGraphQLRequest(client, CREATE_ATTRIBUTE_VALUES, {\n variables: {\n input: newValues.map(({ name, ...rest }) => ({\n name,\n attributeKeyId,\n ...rest,\n })),\n },\n logger,\n });\n logger.info(`Created ${newValues.length} attribute values`);\n }\n\n // Update existing attribute values\n if (existingValues.length > 0) {\n await makeGraphQLRequest(client, UPDATE_ATTRIBUTE_VALUES, {\n variables: {\n input: existingValues.map(({ name, ...rest }) => ({\n id: existingAttributeMap[name]!.id,\n name,\n description: existingAttributeMap[name]!.description,\n color: existingAttributeMap[name]!.color,\n ...rest,\n attributeKeyId,\n })),\n },\n logger,\n });\n logger.info(`Updated ${existingValues.length} attribute values`);\n }\n\n // Delete removed attribute values\n if (removedValues.length > 0 && deleteExtraAttributeValues) {\n await map(\n removedValues,\n async (value) => {\n await makeGraphQLRequest(client, DELETE_ATTRIBUTE_VALUE, {\n variables: { id: existingAttributeMap[value]!.id },\n logger,\n });\n },\n {\n concurrency: 10,\n },\n );\n logger.info(`Deleted ${removedValues.length} attribute values`);\n }\n}\n","import { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { UPDATE_INTL_MESSAGES } from './gqls/message.js';\n\nexport interface IntlMessageInput {\n /** React Intl message ID */\n id: string;\n /** Target React Intl ID to map this message to */\n targetReactIntlId?: string;\n /** Description of the message for translators */\n description?: string;\n /** Default English message content */\n defaultMessage?: string;\n /** Map from locale code to translated string */\n translations?: Record<string, string>;\n}\n\nconst MAX_PAGE_SIZE = 100;\n\n/**\n * Update or create intl messages\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateIntlMessages(\n client: GraphQLClient,\n options: {\n /** List of message inputs */\n input: IntlMessageInput[];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: messages, logger = NOOP_LOGGER } = options;\n // Batch update messages\n await mapSeries(chunk(messages, MAX_PAGE_SIZE), async (page) => {\n await makeGraphQLRequest(client, UPDATE_INTL_MESSAGES, {\n variables: {\n messages: page.map((message) => ({\n ...(message.id.includes('.') ? {} : { id: message.id }),\n defaultMessage: message.defaultMessage,\n targetReactIntlId: message.targetReactIntlId,\n translations: !message.translations\n ? undefined\n : Object.entries(message.translations).map(([locale, value]) => ({\n locale,\n value,\n })),\n })),\n },\n logger,\n });\n });\n}\n\n/**\n * Sync the set of messages from the YML interface into the product\n *\n * @param client - GraphQL client\n * @param messages - messages to sync\n * @returns True upon success, false upon failure\n */\nexport async function syncIntlMessages(\n client: GraphQLClient,\n messages: IntlMessageInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${messages.length}\" messages...`);\n\n // Ensure no duplicates are being uploaded\n const notUnique = messages.filter(\n (message) => messages.filter((pol) => message.id === pol.id).length > 1,\n );\n if (notUnique.length > 0) {\n throw new Error(\n `Failed to upload messages as there were non-unique entries found: ${notUnique\n .map(({ id }) => id)\n .join(',')}`,\n );\n }\n\n try {\n logger.info(`Upserting \"${messages.length}\" new messages...`);\n await updateIntlMessages(client, { input: messages, logger });\n logger.info(`Successfully synced ${messages.length} messages!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create messages! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import { ScopeName } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllTeams, type Team } from './fetchAllTeams.js';\nimport { UPDATE_TEAM, CREATE_TEAM } from './gqls/team.js';\n\nexport interface TeamInput {\n /** The display name of the team */\n name: string;\n /** Team description */\n description: string;\n /** SSO department for automated provisioning */\n 'sso-department'?: string;\n /** SSO group name for automated provisioning */\n 'sso-group'?: string;\n /** SSO title mapping for automated provisioning */\n 'sso-title'?: string;\n /** List of user emails on the team */\n users?: string[];\n /** List of scopes that the team should have */\n scopes?: ScopeName[];\n}\n\n/**\n * Input to create a new team\n *\n * @param client - GraphQL client\n * @param team - Input\n * @param options - Options\n * @returns Created team\n */\nexport async function createTeam(\n client: GraphQLClient,\n options: {\n /** Team to create */\n input: TeamInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<Team, 'id' | 'name'>> {\n const { input: team, logger = NOOP_LOGGER } = options;\n const input = {\n name: team.name,\n description: team.description,\n ssoTitle: team['sso-title'],\n ssoDepartment: team['sso-department'],\n ssoGroup: team['sso-group'],\n scopes: team.scopes,\n userEmails: team.users,\n };\n\n const { createTeam } = await makeGraphQLRequest<{\n /** Create team mutation */\n createTeam: {\n /** Created team */\n team: Team;\n };\n }>(client, CREATE_TEAM, {\n variables: { input },\n logger,\n });\n return createTeam.team;\n}\n\n/**\n * Input to update teams\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Updated team\n */\nexport async function updateTeam(\n client: GraphQLClient,\n options: {\n /** Team input to update */\n input: TeamInput & {\n /** ID of team to update */\n id: string;\n };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<Team, 'id' | 'name'>> {\n const { input: team, logger = NOOP_LOGGER } = options;\n const teamId = team.id;\n const { updateTeam } = await makeGraphQLRequest<{\n /** Update team mutation */\n updateTeam: {\n /** Updated team */\n team: Team;\n };\n }>(client, UPDATE_TEAM, {\n variables: {\n input: {\n id: teamId,\n name: team.name,\n description: team.description,\n ssoTitle: team['sso-title'],\n ssoDepartment: team['sso-department'],\n ssoGroup: team['sso-group'],\n scopes: team.scopes,\n userEmails: team.users,\n },\n },\n logger,\n });\n return updateTeam.team;\n}\n\n/**\n * Sync the teams\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncTeams(\n client: GraphQLClient,\n inputs: TeamInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n // Fetch existing\n logger.info(`Syncing \"${inputs.length}\" teams...`);\n\n let encounteredError = false;\n\n // Fetch existing\n const existingTeams = await fetchAllTeams(client, { logger });\n\n // Look up by name\n const teamsByName: { [k in string]: Pick<Team, 'id' | 'name'> } = keyBy(existingTeams, 'name');\n\n // Create new teams\n const newTeams = inputs.filter((input) => !teamsByName[input.name]);\n const updatedTeams = inputs.filter((input) => !!teamsByName[input.name]);\n\n // Create new teams\n await mapSeries(newTeams, async (team) => {\n try {\n const newTeam = await createTeam(client, { input: team, logger });\n teamsByName[newTeam.name] = newTeam;\n logger.info(`Successfully created team \"${team.name}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync team \"${team.name}\"! - ${(err as Error).message}`);\n }\n });\n\n // Update all teams\n await mapSeries(updatedTeams, async (input) => {\n try {\n const newTeam = await updateTeam(client, {\n input: { ...input, id: teamsByName[input.name]!.id },\n logger,\n });\n teamsByName[newTeam.name] = newTeam;\n logger.info(`Successfully updated team \"${input.name}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync team \"${input.name}\"! - ${(err as Error).message}`);\n }\n });\n\n return !encounteredError;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\nexport const ATTRIBUTE_KEYS_REQUESTS = gql`\n query TranscendCliAttributeKeys($first: Int!, $offset: Int!) {\n attributeKeys(\n filterBy: { enabledOn: [request] }\n first: $first\n useMaster: false\n offset: $offset\n ) {\n nodes {\n id\n name\n type\n }\n }\n }\n`;\n","import got, { type Got } from 'got';\n\n/**\n * Instantiate an instance of got that is capable of making requests\n * to a sombra gateway.\n *\n * @param transcendUrl - URL of Transcend API\n * @returns The instance of got that is capable of making requests to the customer ingress\n */\nexport function createTranscendConsentGotInstance(transcendUrl: string): Got {\n return (got as unknown as Got).extend({\n prefixUrl: transcendUrl,\n });\n}\n","import { gql } from 'graphql-request';\n\n// ---- FETCH_CONSENT_MANAGER_ID query ----\n\n/** Full response from FETCH_CONSENT_MANAGER_ID */\nexport interface TranscendCliFetchConsentManagerIdResponse {\n /** Consent manager wrapper */\n consentManager: {\n /** Consent manager object */\n consentManager: {\n /** Consent manager / airgap bundle ID */\n id: string;\n };\n };\n}\n\nexport const FETCH_CONSENT_MANAGER_ID = gql`\n query TranscendCliFetchConsentManagerId {\n consentManager {\n consentManager {\n id\n }\n }\n }\n`;\n\n// ---- FETCH_CONSENT_MANAGER query ----\n\n/** Consent manager configuration */\nexport interface TranscendConsentManagerConfigGql {\n /** Configured domains */\n domains: string[];\n /** Consent precedence setting */\n consentPrecedence: string;\n /** Unknown request policy */\n unknownRequestPolicy: string;\n /** Unknown cookie policy */\n unknownCookiePolicy: string;\n /** Sync endpoint URL */\n syncEndpoint: string;\n /** Telemetry partitioning strategy */\n telemetryPartitioning: string;\n /** Signed IAB agreement status */\n signedIabAgreement: string;\n /** Sync groups setting */\n syncGroups: string;\n /** Partition parameter */\n partition: string;\n}\n\n/** Consent manager node */\nexport interface TranscendConsentManagerGql {\n /** Consent manager / airgap bundle ID */\n id: string;\n /** Production bundle URL */\n bundleURL: string;\n /** Test bundle URL */\n testBundleURL: string;\n /** Configuration settings */\n configuration: TranscendConsentManagerConfigGql;\n /** Partition info */\n partition?: {\n /** Partition value */\n partition: string;\n };\n}\n\n/** Full response from FETCH_CONSENT_MANAGER */\nexport interface TranscendCliFetchConsentManagerResponse {\n /** Consent manager wrapper */\n consentManager: {\n /** Consent manager object */\n consentManager: TranscendConsentManagerGql;\n };\n}\n\nexport const FETCH_CONSENT_MANAGER = gql`\n query TranscendCliFetchConsentManager {\n consentManager {\n consentManager {\n id\n bundleURL\n testBundleURL\n configuration {\n domains\n consentPrecedence\n unknownRequestPolicy\n unknownCookiePolicy\n syncEndpoint\n telemetryPartitioning\n signedIabAgreement\n syncGroups\n partition\n }\n partition {\n partition\n }\n }\n }\n }\n`;\n\n// ---- FETCH_CONSENT_MANAGER_THEME query ----\n\n/** Consent manager theme fields */\nexport interface TranscendConsentManagerThemeGql {\n /** Primary color */\n primaryColor: string;\n /** Font color */\n fontColor: string;\n /** Privacy policy URL */\n privacyPolicy?: string;\n /** Auto-prompt setting */\n prompt: number;\n}\n\n/** Full response from FETCH_CONSENT_MANAGER_THEME */\nexport interface TranscendCliFetchConsentManagerThemeResponse {\n /** Theme wrapper */\n consentManagerTheme: {\n /** Theme object */\n theme: TranscendConsentManagerThemeGql;\n };\n}\n\nexport const FETCH_CONSENT_MANAGER_THEME = gql`\n query TranscendCliFetchConsentManagerTheme($airgapBundleId: ID!) {\n consentManagerTheme(input: { airgapBundleId: $airgapBundleId }) {\n theme {\n primaryColor\n fontColor\n privacyPolicy\n prompt\n }\n }\n }\n`;\n\n// ---- Consent Manager mutations ----\n\n/** Shared response type for mutations that return only clientMutationId */\nexport interface TranscendClientMutationIdResponse {\n /** Mutation result keyed by mutation name */\n [key: string]: {\n /** Client mutation ID */\n clientMutationId: string | null;\n };\n}\n\nexport const CREATE_CONSENT_MANAGER = gql`\n mutation TranscendCliCreateConsentManager($privacyCenterId: ID!) {\n createConsentManager(input: { privacyCenterId: $privacyCenterId }) {\n consentManager {\n id\n }\n }\n }\n`;\n\nexport const UPDATE_CONSENT_MANAGER_VERSION = gql`\n mutation TranscendCliUpdateConsentManager($airgapBundleId: ID!, $version: String!) {\n updateConsentManager(id: $airgapBundleId, input: { version: $version }) {\n clientMutationId\n }\n }\n`;\n\nexport const UPDATE_CONSENT_MANAGER_TO_LATEST = gql`\n mutation TranscendCliUpdateConsentManagerToLatest(\n $airgapBundleId: ID!\n $bundleType: ConsentBundleType!\n ) {\n updateConsentManagerToLatestVersion(id: $airgapBundleId, input: { bundleType: $bundleType }) {\n clientMutationId\n }\n }\n`;\n\nexport const DEPLOY_CONSENT_MANAGER = gql`\n mutation TranscendCliDeployConsentManager($airgapBundleId: ID!, $bundleType: ConsentBundleType!) {\n deployConsentManagerBundle(id: $airgapBundleId, input: { bundleType: $bundleType }) {\n clientMutationId\n }\n }\n`;\n\nexport const UPDATE_CONSENT_MANAGER_DOMAINS = gql`\n mutation TranscendCliUpdateConsentManagerDomains($airgapBundleId: ID!, $domains: [String!]!) {\n updateConsentManagerDomains(input: { id: $airgapBundleId, domains: $domains }) {\n clientMutationId\n }\n }\n`;\n\nexport const UPDATE_CONSENT_MANAGER_PARTITION = gql`\n mutation TranscendCliUpdateConsentManagerPartition($airgapBundleId: ID!, $partitionId: ID!) {\n updateConsentManagerPartition(input: { id: $airgapBundleId, partitionId: $partitionId }) {\n clientMutationId\n }\n }\n`;\n\nexport const UPDATE_LOAD_OPTIONS = gql`\n mutation TranscendCliUpdateLoadOptions($input: UpdateLoadOptionsInput!) {\n updateLoadOptions(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const TOGGLE_UNKNOWN_REQUEST_POLICY = gql`\n mutation TranscendCliToggleUnknownRequestPolicy($input: ToggleUnknownRequestPolicyInput!) {\n toggleUnknownRequestPolicy(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const TOGGLE_UNKNOWN_COOKIE_POLICY = gql`\n mutation TranscendCliToggleUnknownCookiePolicy($input: ToggleUnknownCookiePolicyInput!) {\n toggleUnknownCookiePolicy(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const TOGGLE_TELEMETRY_PARTITION_STRATEGY = gql`\n mutation TranscendCliToggleTelemetryPartitionStrategy(\n $input: ToggleTelemetryPartitionStrategyInput!\n ) {\n toggleTelemetryPartitioning(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const TOGGLE_CONSENT_PRECEDENCE = gql`\n mutation TranscendCliToggleConsentPrecedence($input: ToggleConsentPrecedenceInput!) {\n toggleConsentPrecedence(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const UPDATE_CONSENT_MANAGER_THEME = gql`\n mutation TranscendCliUpdateConsentManagerTheme($input: UpdateConsentManagerThemeInput!) {\n updateConsentManagerTheme(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { ConsentBundleType } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { DEPLOY_CONSENT_MANAGER, UPDATE_CONSENT_MANAGER_TO_LATEST } from './gqls/consentManager.js';\n\n/**\n * Deploy the Consent Manager\n *\n * @param client - GraphQL client\n * @param input - Deploy input\n * @param options - Options\n */\nexport async function deployConsentManager(\n client: GraphQLClient,\n input: {\n /** ID of Consent Manager */\n id: string;\n /** Type of bundle */\n bundleType: ConsentBundleType;\n },\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n await makeGraphQLRequest(client, DEPLOY_CONSENT_MANAGER, {\n variables: { airgapBundleId: input.id, bundleType: input.bundleType },\n logger: options.logger,\n });\n}\n\n/**\n * Update the Consent Manager to the latest airgap.js version\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateConsentManagerToLatest(\n client: GraphQLClient,\n options: {\n /** Consent manager to update */\n input: {\n /** ID of Consent Manager */\n id: string;\n /** Type of bundle */\n bundleType: ConsentBundleType;\n };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: consentManager, logger } = options;\n await makeGraphQLRequest(client, UPDATE_CONSENT_MANAGER_TO_LATEST, {\n variables: { airgapBundleId: consentManager.id, bundleType: consentManager.bundleType },\n logger,\n });\n}\n","import { gql } from 'graphql-request';\n\nexport const CONSENT_MANAGER_ANALYTICS_DATA = gql`\n query TranscendCliConsentManagerAnalyticsData($input: AnalyticsInput!) {\n analyticsData(input: $input) {\n series {\n name\n points {\n key\n value\n }\n }\n }\n }\n`;\n","import { gql } from 'graphql-request';\n\n// ---- Shared experience types ----\n\n/** Region associated with a consent experience */\nexport interface TranscendExperienceRegionGql {\n /** ISO country subdivision code */\n countrySubDivision?: string;\n /** ISO country code */\n country?: string;\n}\n\n/** Experience purpose reference */\nexport interface TranscendExperiencePurposeGql {\n /** Purpose display name */\n name: string;\n /** Purpose slug */\n trackingType: string;\n}\n\n/** Consent experience (regional regime) returned by EXPERIENCES query */\nexport interface TranscendExperienceGql {\n /** Experience ID */\n id: string;\n /** Internal name */\n name: string;\n /** Display name shown to users */\n displayName?: string;\n /** Regions where this experience applies */\n regions: TranscendExperienceRegionGql[];\n /** Whether regions list is inclusive or exclusive */\n operator: string;\n /** Display priority for ordering */\n displayPriority: number;\n /** Behavior on consent expiry */\n onConsentExpiry: string;\n /** Consent expiry duration */\n consentExpiry: number;\n /** Initial view state for auto-prompting */\n viewState: string;\n /** Purposes that can be opted out of */\n purposes: TranscendExperiencePurposeGql[];\n /** Purposes opted out by default */\n optedOutPurposes: TranscendExperiencePurposeGql[];\n /** Browser languages for this experience */\n browserLanguages: string[];\n /** Browser time zones for this experience */\n browserTimeZones: string[];\n}\n\n// ---- EXPERIENCES query ----\n\n/** Full response from the EXPERIENCES query */\nexport interface TranscendCliExperiencesResponse {\n /** Experiences result */\n experiences: {\n /** Total count of experiences */\n totalCount: number;\n /** List of experience nodes */\n nodes: TranscendExperienceGql[];\n };\n}\n\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const EXPERIENCES = gql`\n query TranscendCliExperiences($first: Int!, $offset: Int!) {\n experiences(first: $first, offset: $offset, useMaster: false) {\n totalCount\n nodes {\n id\n name\n displayName\n regions {\n countrySubDivision\n country\n }\n operator\n displayPriority\n onConsentExpiry\n consentExpiry\n viewState\n purposes {\n name\n trackingType\n }\n optedOutPurposes {\n name\n trackingType\n }\n browserLanguages\n browserTimeZones\n }\n }\n }\n`;\n\n// ---- UPDATE_CONSENT_EXPERIENCE mutation ----\n\n/** Full response from the UPDATE_CONSENT_EXPERIENCE mutation */\nexport interface TranscendCliUpdateConsentExperienceResponse {\n /** Mutation result */\n updateExperience: {\n /** Client mutation ID */\n clientMutationId: string | null;\n };\n}\n\nexport const UPDATE_CONSENT_EXPERIENCE = gql`\n mutation TranscendCliUpdateConsentExperience($input: UpdateExperienceInput!) {\n updateExperience(input: $input) {\n clientMutationId\n }\n }\n`;\n\n// ---- CREATE_CONSENT_EXPERIENCE mutation ----\n\n/** Full response from the CREATE_CONSENT_EXPERIENCE mutation */\nexport interface TranscendCliCreateConsentExperienceResponse {\n /** Mutation result */\n createExperience: {\n /** Client mutation ID */\n clientMutationId: string | null;\n };\n}\n\nexport const CREATE_CONSENT_EXPERIENCE = gql`\n mutation TranscendCliCreateConsentExperience($input: CreateExperienceInput!) {\n createExperience(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { InitialViewState, BrowserLanguage, OnConsentExpiry } from '@transcend-io/airgap.js-types';\nimport {\n ConsentPrecedenceOption,\n UnknownRequestPolicy,\n TelemetryPartitionStrategy,\n RegionsOperator,\n IsoCountrySubdivisionCode,\n IsoCountryCode,\n BrowserTimeZone,\n SignedIabAgreementOption,\n} from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport {\n FETCH_CONSENT_MANAGER_ID,\n FETCH_CONSENT_MANAGER,\n FETCH_CONSENT_MANAGER_THEME,\n type TranscendConsentManagerThemeGql,\n type TranscendCliFetchConsentManagerThemeResponse,\n} from './gqls/consentManager.js';\nimport { CONSENT_MANAGER_ANALYTICS_DATA } from './gqls/consentManagerMetrics.js';\nimport { EXPERIENCES } from './gqls/experiences.js';\n\nexport interface ConsentManager {\n /** ID of consent manager */\n id: string;\n /** Production bundle URL */\n bundleURL: string;\n /** Test bundle URL */\n testBundleURL: string;\n /** Configuration of consent manager */\n configuration: {\n /** Domain list */\n domains: string[];\n /** Consent precedence of user vs signal */\n consentPrecedence: ConsentPrecedenceOption;\n /** Unknown request policy */\n unknownRequestPolicy: UnknownRequestPolicy;\n /** Unknown cookie policy */\n unknownCookiePolicy: UnknownRequestPolicy;\n /** Sync endpoint */\n syncEndpoint: string;\n /** Telemetry partitioning */\n telemetryPartitioning: TelemetryPartitionStrategy;\n /** Signed IAB agreement */\n signedIabAgreement: SignedIabAgreementOption;\n /** Sync groups */\n syncGroups: string;\n /** Partition parameter */\n partition: string;\n };\n /** When using a custom partition, this is the partition value */\n partition?: {\n /** Partition value */\n partition: string;\n };\n}\n\n/**\n * Fetch consent manager\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Consent manager ID in organization\n */\nexport async function fetchConsentManager(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<ConsentManager> {\n const {\n consentManager: { consentManager },\n } = await makeGraphQLRequest<{\n /** Consent manager query */\n consentManager: {\n /** Consent manager object */\n consentManager: ConsentManager;\n };\n }>(client, FETCH_CONSENT_MANAGER, { logger: options.logger });\n return consentManager;\n}\n\n/**\n * Fetch consent manager ID\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Consent manager ID in organization\n */\nexport async function fetchConsentManagerId(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Max number of requests to send */\n maxRequests?: number;\n } = {},\n): Promise<string> {\n const {\n consentManager: { consentManager },\n } = await makeGraphQLRequest<{\n /** Consent manager query */\n consentManager: {\n /** Consent manager object */\n consentManager: {\n /** ID of bundle */\n id: string;\n };\n };\n }>(client, FETCH_CONSENT_MANAGER_ID, {\n logger: options.logger,\n maxRetries: options.maxRequests,\n });\n return consentManager.id;\n}\n\nconst PAGE_SIZE = 50;\n\nexport interface ConsentExperience {\n /** ID of experience */\n id: string;\n /** Name of experience */\n name: string;\n /** Experience display name */\n displayName?: string;\n /** Region that define this regional experience */\n regions: {\n /** Sub division */\n countrySubDivision?: IsoCountrySubdivisionCode;\n /** Country */\n country?: IsoCountryCode;\n }[];\n /** In vs not in operator */\n operator: RegionsOperator;\n /** Priority of experience */\n displayPriority: number;\n /** View state to prompt when auto prompting is enabled */\n viewState: InitialViewState;\n /** Consent expiry setting */\n onConsentExpiry: OnConsentExpiry;\n /** Consent expiry */\n consentExpiry: number;\n /** Purposes that can be opted out of in a particular experience */\n purposes: {\n /** Name of purpose */\n name: string;\n /** Purpose slug */\n trackingType: string;\n }[];\n /** Purposes that are opted out by default in a particular experience */\n optedOutPurposes: {\n /** Name of purpose */\n name: string;\n /** Purpose slug */\n trackingType: string;\n }[];\n /** Browser languages that define this regional experience */\n browserLanguages: BrowserLanguage[];\n /** Browser time zones that define this regional experience */\n browserTimeZones: BrowserTimeZone[];\n}\n\n/**\n * Fetch consent manager experiences\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Consent manager experiences in the organization\n */\nexport async function fetchConsentManagerExperiences(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<ConsentExperience[]> {\n const experiences: ConsentExperience[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n experiences: { nodes },\n } = await makeGraphQLRequest<{\n /** Consent experience */\n experiences: {\n /** List */\n nodes: ConsentExperience[];\n };\n }>(client, EXPERIENCES, {\n variables: { first: PAGE_SIZE, offset },\n logger: options.logger,\n });\n experiences.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return experiences.sort((a, b) => a.name.localeCompare(b.name));\n}\n\n/**\n * The allowed bin sizes for pulling consent metrics\n */\nexport enum ConsentManagerMetricBin {\n Hourly = '1h',\n Daily = '1d',\n}\n\nexport interface ConsentManagerMetric {\n /** Name of metric */\n name: string;\n /** The metrics */\n points: {\n /** Key of metric */\n key: string;\n /** Value of metric */\n value: string;\n }[];\n}\n\n/**\n * Fetch consent manager analytics data\n *\n * @param client - GraphQL client\n * @param input - Input for fetching data\n * @param options - Options\n * @returns Consent manager purposes in the organization\n */\nexport async function fetchConsentManagerAnalyticsData(\n client: GraphQLClient,\n input: {\n /** Data source */\n dataSource:\n | 'PRIVACY_SIGNAL_TIMESERIES'\n | 'CONSENT_CHANGES_TIMESERIES'\n | 'CONSENT_SESSIONS_BY_REGIME';\n /** Start date, in ISO string format */\n startDate: string;\n /** End date, in ISO string format */\n endDate: string;\n /** Force refetching */\n forceRefetch?: boolean;\n /** Airgap bundle ID */\n airgapBundleId: string;\n /** Bin interval */\n binInterval: ConsentManagerMetricBin;\n /** Whether or not to smooth the time series */\n smoothTimeseries: false;\n },\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<ConsentManagerMetric[]> {\n const {\n analyticsData: { series },\n } = await makeGraphQLRequest<{\n /** Analytics data response */\n analyticsData: {\n /** Consent manager metrics */\n series: ConsentManagerMetric[];\n };\n }>(client, CONSENT_MANAGER_ANALYTICS_DATA, {\n variables: { input },\n logger: options.logger,\n });\n return series;\n}\n\n/**\n * Fetch consent manager theme\n *\n * @param client - GraphQL client\n * @param airgapBundleId - Airgap bundle ID to fetch for\n * @param options - Options\n * @returns Consent manager ID in organization\n */\nexport async function fetchConsentManagerTheme(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy: {\n /** Airgap bundle ID to fetch for */\n airgapBundleId: string;\n };\n },\n): Promise<TranscendConsentManagerThemeGql> {\n const {\n consentManagerTheme: { theme },\n } = await makeGraphQLRequest<TranscendCliFetchConsentManagerThemeResponse>(\n client,\n FETCH_CONSENT_MANAGER_THEME,\n {\n variables: { airgapBundleId: options.filterBy.airgapBundleId },\n logger: options.logger,\n },\n );\n return theme;\n}\n","/** Service associated with a cookie or data flow */\nexport interface TranscendCookieServiceGql {\n /** Service ID */\n id: string;\n /** Human-readable service title */\n title: string;\n /** Integration slug */\n integrationName: string;\n}\n\n/** Service fields shared by cookies and data flows */\nexport const SERVICE_FIELDS = `\n id\n title\n integrationName\n`;\n\n/** Tracking purpose assigned to a cookie or data flow */\nexport interface TranscendTrackingPurposeGql {\n /** Purpose ID */\n id: string;\n /** Purpose display name */\n name: string;\n /** Purpose slug (e.g. \"Advertising\", \"Analytics\") */\n trackingType: string;\n}\n\n/** Tracking purpose fields */\nexport const TRACKING_PURPOSE_FIELDS = `\n id\n name\n trackingType\n`;\n","import type { ConsentTrackerSource, ConsentTrackerStatus } from '@transcend-io/privacy-types';\nimport { gql } from 'graphql-request';\n\nimport {\n ATTRIBUTE_VALUE_FIELDS,\n OWNER_FIELDS,\n TEAM_FIELDS,\n type TranscendAttributeValueGql,\n type TranscendOwnerGql,\n type TranscendTeamGql,\n} from '../../gqls/shared.js';\nimport {\n SERVICE_FIELDS,\n TRACKING_PURPOSE_FIELDS,\n type TranscendCookieServiceGql,\n type TranscendTrackingPurposeGql,\n} from './shared.js';\n\n// ---- Shared cookie types ----\n\n/** Cookie domain with occurrence count */\nexport interface TranscendCookieDomainGql {\n /** Domain ID */\n id: string;\n /** Domain name */\n domain: string;\n /** Number of occurrences on this domain */\n occurrences: number;\n}\n\n/** Cookie node returned by COOKIES query */\nexport interface TranscendCookieGql {\n /** Cookie ID */\n id: string;\n /** Cookie name */\n name: string;\n /** Whether this is a regex pattern */\n isRegex: boolean;\n /** Description */\n description?: string;\n /** Tracking purpose slugs (string array) */\n trackingPurposes: string[];\n /** Resolved tracking purposes */\n purposes: TranscendTrackingPurposeGql[];\n /** Frequency of occurrence (0-1) */\n frequency: number;\n /** Associated service */\n service?: TranscendCookieServiceGql;\n /** Whether marked as junk */\n isJunk: boolean;\n /** How the tracker was discovered */\n source: ConsentTrackerSource;\n /** Triage status */\n status: ConsentTrackerStatus;\n /** Assigned owners */\n owners: TranscendOwnerGql[];\n /** Assigned teams */\n teams: TranscendTeamGql[];\n /** Custom attribute values */\n attributeValues: TranscendAttributeValueGql[];\n /** Creation timestamp */\n createdAt: string;\n /** Last updated timestamp */\n updatedAt: string;\n /** Last seen by telemetry */\n lastDiscoveredAt?: string;\n /** Domains this cookie appears on */\n domains: TranscendCookieDomainGql[];\n /** Total telemetry occurrences */\n occurrences: number;\n /** Number of sites seen on (all time) */\n consentSiteCountAllTime: number;\n /** Number of sites seen on (last week) */\n consentSiteCountLastWeek: number;\n}\n\n/** Input for updating or creating a cookie */\nexport interface TranscendUpdateCookieInputGql {\n /** Cookie name (used as identifier for upsert) */\n name: string;\n /** Tracking purpose slugs */\n trackingPurposes?: string[];\n /** Purpose IDs to assign */\n purposeIds?: string[];\n /** Description */\n description?: string;\n /** Service integration name */\n service?: string;\n /** Mark as junk */\n isJunk?: boolean;\n /** Triage status */\n status?: ConsentTrackerStatus;\n /** Whether this is a regex pattern */\n isRegex?: boolean;\n /** How the tracker was discovered */\n source?: ConsentTrackerSource;\n}\n\n// ---- COOKIES query ----\n\n/** Full response from the COOKIES query */\nexport interface TranscendCliCookiesResponse {\n /** Cookies result */\n cookies: {\n /** List of cookie nodes */\n nodes: TranscendCookieGql[];\n /** Total count of matching cookies */\n totalCount: number;\n };\n}\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const COOKIES = gql`\n query TranscendCliCookies(\n $input: AirgapBundleInput!\n $first: Int!\n $offset: Int!\n $filterBy: CookiesFiltersInput\n $orderBy: [CookieOrder!]\n ) {\n cookies(\n input: $input\n first: $first\n offset: $offset\n filterBy: $filterBy\n orderBy: $orderBy\n useMaster: false\n ) {\n totalCount\n nodes {\n id\n name\n isRegex\n description\n trackingPurposes\n purposes { ${TRACKING_PURPOSE_FIELDS} }\n frequency\n service { ${SERVICE_FIELDS} }\n isJunk\n source\n status\n owners { ${OWNER_FIELDS} }\n teams { ${TEAM_FIELDS} }\n attributeValues { ${ATTRIBUTE_VALUE_FIELDS} }\n createdAt\n updatedAt\n lastDiscoveredAt\n domains {\n id\n domain\n occurrences\n }\n occurrences\n consentSiteCountAllTime\n consentSiteCountLastWeek\n }\n }\n }\n`;\n\n// ---- UPDATE_OR_CREATE_COOKIES mutation ----\n\n/** Full response from the UPDATE_OR_CREATE_COOKIES mutation */\nexport interface TranscendCliUpdateOrCreateCookiesResponse {\n /** Mutation result */\n updateOrCreateCookies: {\n /** Client mutation ID */\n clientMutationId: string | null;\n };\n}\n\nexport const UPDATE_OR_CREATE_COOKIES = gql`\n mutation TranscendCliUpdateOrCreateCookies(\n $cookies: [UpdateOrCreateCookieInput!]!\n $airgapBundleId: ID!\n ) {\n updateOrCreateCookies(input: { airgapBundleId: $airgapBundleId, cookies: $cookies }) {\n clientMutationId\n }\n }\n`;\n\n// ---- DELETE_COOKIES mutation ----\n\n/** Full response from the DELETE_COOKIES mutation */\nexport interface TranscendCliDeleteCookiesResponse {\n /** Mutation result */\n deleteCookies: {\n /** Client mutation ID */\n clientMutationId: string | null;\n };\n}\n\nexport const DELETE_COOKIES = gql`\n mutation TranscendCliDeleteCookies($input: DeleteCookiesInput!) {\n deleteCookies(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { ConsentTrackerStatus, OrderDirection } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { fetchConsentManagerId } from './fetchConsentManagerId.js';\nimport {\n COOKIES,\n type TranscendCookieGql,\n type TranscendCliCookiesResponse,\n} from './gqls/cookies.js';\n\n/** Sort order for cookie queries */\nexport interface CookieOrder {\n /** Field to sort by */\n field: string;\n /** Sort direction */\n direction: OrderDirection;\n}\n\nconst PAGE_SIZE = 20;\n\nconst DEFAULT_COOKIE_ORDER: CookieOrder[] = [\n { field: 'createdAt', direction: OrderDirection.Asc },\n { field: 'name', direction: OrderDirection.Asc },\n];\n\n/**\n * Fetch all Cookies in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All Cookies in the organization\n */\nexport async function fetchAllCookies(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** The status to fetch */\n status?: ConsentTrackerStatus;\n };\n /** Sort ordering (defaults to createdAt ASC, name ASC) */\n orderBy?: CookieOrder[];\n } = {},\n): Promise<TranscendCookieGql[]> {\n const {\n logger,\n filterBy: { status = ConsentTrackerStatus.Live } = {},\n orderBy = DEFAULT_COOKIE_ORDER,\n } = options;\n const cookies: TranscendCookieGql[] = [];\n let offset = 0;\n\n const airgapBundleId = await fetchConsentManagerId(client, { logger });\n\n let shouldContinue = false;\n do {\n const {\n cookies: { nodes },\n } = await makeGraphQLRequest<TranscendCliCookiesResponse>(client, COOKIES, {\n variables: {\n input: { airgapBundleId },\n first: PAGE_SIZE,\n offset,\n filterBy: { status },\n orderBy,\n },\n logger,\n });\n cookies.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return cookies.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import type {\n ConsentTrackerSource,\n ConsentTrackerStatus,\n DataFlowScope,\n} from '@transcend-io/privacy-types';\nimport { gql } from 'graphql-request';\n\nimport {\n ATTRIBUTE_VALUE_FIELDS,\n OWNER_FIELDS,\n TEAM_FIELDS,\n type TranscendAttributeValueGql,\n type TranscendOwnerGql,\n type TranscendTeamGql,\n} from '../../gqls/shared.js';\nimport {\n SERVICE_FIELDS,\n TRACKING_PURPOSE_FIELDS,\n type TranscendCookieServiceGql,\n type TranscendTrackingPurposeGql,\n} from './shared.js';\n\n// ---- Shared data flow types ----\n\n/** Data flow node returned by DATA_FLOWS query and UPDATE_DATA_FLOWS mutation */\nexport interface TranscendDataFlowGql {\n /** Data flow ID */\n id: string;\n /** URL/host value */\n value: string;\n /** Scope type (HOST, PATH, REGEX, etc.) */\n type: DataFlowScope;\n /** Description */\n description?: string;\n /** Tracking purpose slugs */\n trackingType: string[];\n /** Resolved tracking purposes */\n purposes: TranscendTrackingPurposeGql[];\n /** Frequency of occurrence (0-1) */\n frequency: number;\n /** Associated service */\n service?: TranscendCookieServiceGql;\n /** Whether marked as junk */\n isJunk: boolean;\n /** How the tracker was discovered */\n source: ConsentTrackerSource;\n /** Triage status */\n status: ConsentTrackerStatus;\n /** Assigned owners */\n owners: TranscendOwnerGql[];\n /** Assigned teams */\n teams: TranscendTeamGql[];\n /** Custom attribute values */\n attributeValues: TranscendAttributeValueGql[];\n /** Creation timestamp */\n createdAt: string;\n /** Last updated timestamp */\n updatedAt: string;\n /** Last seen by telemetry */\n lastDiscoveredAt?: string;\n /** Total telemetry occurrences */\n occurrences: number;\n /** Number of sites seen on (all time) */\n consentSiteCountAllTime: number;\n /** Number of sites seen on (last week) */\n consentSiteCountLastWeek: number;\n}\n\n/** Input for updating a data flow */\nexport interface TranscendUpdateDataFlowInputGql {\n /** Data flow ID */\n id: string;\n /** URL/host value */\n value?: string;\n /** Scope type */\n type?: DataFlowScope;\n /** Tracking purpose slugs */\n trackingType?: string[];\n /** Purpose IDs to assign */\n purposeIds?: string[];\n /** Description */\n description?: string;\n /** Service integration name */\n service?: string;\n /** Mark as junk */\n isJunk?: boolean;\n /** Triage status */\n status?: ConsentTrackerStatus;\n}\n\n// ---- Shared field selection for mutation responses ----\n\nconst DATA_FLOW_RESPONSE_FIELDS = `\n id\n value\n type\n description\n trackingType\n purposes { ${TRACKING_PURPOSE_FIELDS} }\n frequency\n service { ${SERVICE_FIELDS} }\n isJunk\n source\n status\n createdAt\n updatedAt\n lastDiscoveredAt\n occurrences\n consentSiteCountAllTime\n consentSiteCountLastWeek\n`;\n\n// ---- CREATE_DATA_FLOWS mutation ----\n\n/** Full response from the CREATE_DATA_FLOWS mutation */\nexport interface TranscendCliCreateDataFlowsResponse {\n /** Mutation result */\n createDataFlows: {\n /** Created data flows (IDs only) */\n dataFlows: {\n /** Data flow ID */\n id: string;\n }[];\n };\n}\n\nexport const CREATE_DATA_FLOWS = gql`\n mutation TranscendCliCreateDataFlows(\n $dataFlows: [DataFlowInput!]!\n $airgapBundleId: ID!\n $classifyService: Boolean\n ) {\n createDataFlows(\n input: {\n airgapBundleId: $airgapBundleId\n dataFlows: $dataFlows\n classifyService: $classifyService\n }\n ) {\n dataFlows {\n id\n }\n }\n }\n`;\n\n// ---- UPDATE_DATA_FLOWS mutation ----\n\n/** Full response from the UPDATE_DATA_FLOWS mutation */\nexport interface TranscendCliUpdateDataFlowsResponse {\n /** Mutation result */\n updateDataFlows: {\n /** Updated data flows with full fields */\n dataFlows: TranscendDataFlowGql[];\n };\n}\n\nexport const UPDATE_DATA_FLOWS = gql`\n mutation TranscendCliUpdateDataFlows(\n $airgapBundleId: ID!\n $dataFlows: [UpdateDataFlowInput!]!\n $classifyService: Boolean\n ) {\n updateDataFlows(\n input: {\n airgapBundleId: $airgapBundleId\n dataFlows: $dataFlows\n classifyService: $classifyService\n }\n ) {\n dataFlows { ${DATA_FLOW_RESPONSE_FIELDS} }\n }\n }\n`;\n\n// ---- DATA_FLOWS query ----\n\n/** Full response from the DATA_FLOWS query */\nexport interface TranscendCliDataFlowsResponse {\n /** Data flows result */\n dataFlows: {\n /** List of data flow nodes */\n nodes: TranscendDataFlowGql[];\n /** Total count of matching data flows */\n totalCount: number;\n };\n}\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_FLOWS = gql`\n query TranscendCliDataFlows(\n $input: AirgapBundleInput!\n $first: Int!\n $offset: Int!\n $filterBy: DataFlowsFiltersInput\n $orderBy: [DataFlowOrder!]\n ) {\n dataFlows(\n input: $input\n first: $first\n offset: $offset\n filterBy: $filterBy\n orderBy: $orderBy\n useMaster: false\n ) {\n totalCount\n nodes {\n id\n value\n type\n description\n trackingType\n purposes { ${TRACKING_PURPOSE_FIELDS} }\n frequency\n service { ${SERVICE_FIELDS} }\n isJunk\n source\n status\n owners { ${OWNER_FIELDS} }\n teams { ${TEAM_FIELDS} }\n attributeValues { ${ATTRIBUTE_VALUE_FIELDS} }\n createdAt\n updatedAt\n lastDiscoveredAt\n occurrences\n consentSiteCountAllTime\n consentSiteCountLastWeek\n }\n }\n }\n`;\n\n// ---- DELETE_DATA_FLOWS mutation ----\n\n/** Full response from the DELETE_DATA_FLOWS mutation */\nexport interface TranscendCliDeleteDataFlowsResponse {\n /** Mutation result */\n deleteDataFlows: {\n /** Client mutation ID */\n clientMutationId: string | null;\n };\n}\n\nexport const DELETE_DATA_FLOWS = gql`\n mutation TranscendCliDeleteDataFlows($input: DeleteDataFlowsInput!) {\n deleteDataFlows(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { ConsentTrackerStatus, OrderDirection } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { fetchConsentManagerId } from './fetchConsentManagerId.js';\nimport {\n DATA_FLOWS,\n type TranscendDataFlowGql,\n type TranscendCliDataFlowsResponse,\n} from './gqls/dataFlows.js';\n\n/** Sort order for data flow queries */\nexport interface DataFlowOrder {\n /** Field to sort by */\n field: string;\n /** Sort direction */\n direction: OrderDirection;\n}\n\nconst PAGE_SIZE = 20;\n\nconst DEFAULT_DATA_FLOW_ORDER: DataFlowOrder[] = [\n { field: 'createdAt', direction: OrderDirection.Asc },\n { field: 'value', direction: OrderDirection.Asc },\n];\n\n/**\n * Fetch all DataFlows in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All DataFlows in the organization\n */\nexport async function fetchAllDataFlows(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** The status to fetch */\n status?: ConsentTrackerStatus;\n };\n /** Sort ordering (defaults to createdAt ASC, value ASC) */\n orderBy?: DataFlowOrder[];\n } = {},\n): Promise<TranscendDataFlowGql[]> {\n const {\n logger,\n filterBy: { status = ConsentTrackerStatus.Live } = {},\n orderBy = DEFAULT_DATA_FLOW_ORDER,\n } = options;\n const dataFlows: TranscendDataFlowGql[] = [];\n let offset = 0;\n\n const airgapBundleId = await fetchConsentManagerId(client, { logger });\n\n let shouldContinue = false;\n do {\n const {\n dataFlows: { nodes },\n } = await makeGraphQLRequest<TranscendCliDataFlowsResponse>(client, DATA_FLOWS, {\n variables: {\n input: { airgapBundleId },\n first: PAGE_SIZE,\n offset,\n filterBy: {\n status,\n ...(status === ConsentTrackerStatus.NeedsReview ? { showZeroActivity: true } : {}),\n },\n orderBy,\n },\n logger,\n });\n dataFlows.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return dataFlows.sort((a, b) => a.value.localeCompare(b.value));\n}\n","import { gql } from 'graphql-request';\n\nexport const FETCH_PRIVACY_CENTER_ID = gql`\n query TranscendCliFetchPrivacyCenterId($url: String!) {\n privacyCenter(lookup: { url: $url }) {\n id\n }\n }\n`;\n\nexport const DEPLOYED_PRIVACY_CENTER_URL = gql`\n query TranscendCliDeployedPrivacyCenterUrl {\n organization {\n deployedPrivacyCenterUrl\n }\n }\n`;\n\nexport const PRIVACY_CENTER = gql`\n query TranscendCliFetchPrivacyCenters($url: String!) {\n privacyCenter(lookup: { url: $url }) {\n id\n url\n isDisabled\n showPrivacyRequestButton\n showPolicies\n showTrackingTechnologies\n showCookies\n showDataFlows\n showConsentManager\n showManageYourPrivacy\n showMarketingPreferences\n locales\n defaultLocale\n preferBrowserDefaultLocale\n supportEmail\n replyToEmail\n useNoReplyEmailAddress\n useCustomEmailDomain\n transformAccessReportJsonToCsv\n themeStr\n }\n }\n`;\n\nexport const UPDATE_PRIVACY_CENTER = gql`\n mutation TranscendCliUpdatePrivacyCenter($input: UpdatePrivacyCenterInput!) {\n updatePrivacyCenter(input: $input) {\n clientMutationId\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { DEPLOYED_PRIVACY_CENTER_URL, FETCH_PRIVACY_CENTER_ID } from './gqls/privacyCenter.js';\n\n/**\n * Fetch default privacy center URL\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Privacy center URL in organization\n */\nexport async function fetchPrivacyCenterUrl(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<string> {\n const { organization } = await makeGraphQLRequest<{\n /** Organization */\n organization: {\n /** URL */\n deployedPrivacyCenterUrl: string;\n };\n }>(client, DEPLOYED_PRIVACY_CENTER_URL, { logger: options.logger });\n return organization.deployedPrivacyCenterUrl;\n}\n\n/**\n * Fetch privacy center ID\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Privacy center ID in organization\n */\nexport async function fetchPrivacyCenterId(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** URL to look up */\n url?: string;\n };\n } = {},\n): Promise<string> {\n const { logger, filterBy: { url } = {} } = options;\n let urlToUse = url;\n if (!urlToUse) {\n urlToUse = await fetchPrivacyCenterUrl(client, { logger });\n }\n const { privacyCenter } = await makeGraphQLRequest<{\n /** Privacy center query */\n privacyCenter: {\n /** ID of bundle */\n id: string;\n };\n }>(client, FETCH_PRIVACY_CENTER_ID, {\n variables: { url: urlToUse },\n logger,\n });\n return privacyCenter.id;\n}\n","import { gql } from 'graphql-request';\n\nexport const POLICIES = gql`\n query TranscendCliFetchPolicies($url: String!) {\n privacyCenterPolicies(lookup: { url: $url }) {\n id\n title {\n defaultMessage\n }\n disableEffectiveOn\n disabledLocales\n versions {\n effectiveOn\n content {\n defaultMessage\n }\n }\n }\n }\n`;\n\nexport const UPDATE_POLICIES = gql`\n mutation TranscendCliUpdatePolicies($policies: [PolicyInput!]!, $privacyCenterId: ID!) {\n updatePolicies(\n input: { privacyCenterId: $privacyCenterId, policies: $policies, skipPublish: true }\n ) {\n clientMutationId\n }\n }\n`;\n","import type { LocaleValue } from '@transcend-io/internationalization';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { fetchPrivacyCenterUrl } from './fetchPrivacyCenterId.js';\nimport { POLICIES } from './gqls/policy.js';\n\nexport interface Policy {\n /** ID of policy */\n id: string;\n /** Title of policy */\n title: {\n /** Default message */\n defaultMessage: string;\n };\n /** Disabled locales */\n disabledLocales: LocaleValue[];\n /** Versions */\n versions: {\n /** Message content */\n content: {\n /** Default message */\n defaultMessage: string;\n };\n }[];\n}\n\n/**\n * Fetch all policies in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All policies in the organization\n */\nexport async function fetchAllPolicies(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Policy[]> {\n const { logger } = options;\n const deployedPrivacyCenterUrl = await fetchPrivacyCenterUrl(client, { logger });\n const { privacyCenterPolicies } = await makeGraphQLRequest<{\n /** Policies */\n privacyCenterPolicies: Policy[];\n }>(client, POLICIES, {\n variables: { url: deployedPrivacyCenterUrl },\n logger,\n });\n\n return privacyCenterPolicies.sort((a, b) =>\n a.title.defaultMessage.localeCompare(b.title.defaultMessage),\n );\n}\n","import type { LocaleValue } from '@transcend-io/internationalization';\nimport { PrivacyCenterThemePartial } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { fetchPrivacyCenterUrl } from './fetchPrivacyCenterId.js';\nimport { PRIVACY_CENTER } from './gqls/privacyCenter.js';\n\nexport interface PrivacyCenter {\n /** ID of the privacy center */\n id: string;\n /** The URL of the privacy center */\n url: string;\n /** Whether or not the entire privacy center is enabled or disabled */\n isDisabled: boolean;\n /** Whether or not to show the privacy requests button */\n showPrivacyRequestButton: boolean;\n /** Whether or not to show the policies page */\n showPolicies: boolean;\n /** Whether or not to show the tracking technologies page */\n showTrackingTechnologies: boolean;\n /** Whether or not to show the cookies on the tracking technologies page */\n showCookies: boolean;\n /** Whether or not to show the data flows on the tracking technologies page */\n showDataFlows: boolean;\n /** Whether or not to show the consent manager opt out options on the tracking technologies page */\n showConsentManager: boolean;\n /** Whether or not to show the manage your privacy page */\n showManageYourPrivacy: boolean;\n /** Whether or not to show the marketing preferences page */\n showMarketingPreferences: boolean;\n /** What languages are supported for the privacy center */\n locales: LocaleValue[];\n /** The default locale for the privacy center */\n defaultLocale: LocaleValue;\n /** Whether or not to prefer the browser default locale */\n preferBrowserDefaultLocale: boolean;\n /** The email addresses of the employees within your company that are the go-to individuals for managing this privacy center */\n supportEmail: string;\n /** The email addresses of the employees within your company that are the go-to individuals for managing this privacy center */\n replyToEmail: string;\n /** Whether or not to send emails from a no reply email */\n useNoReplyEmailAddress: boolean;\n /** Whether or not to use a custom email domain */\n useCustomEmailDomain: boolean;\n /** Whether or not to transcend access requests from JSON to CSV */\n transformAccessReportJsonToCsv: boolean;\n /** The theme object of colors to display on the privacy center */\n theme: PrivacyCenterThemePartial;\n}\n\n/**\n * Fetch all privacy centers in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All privacy centers in the organization\n */\nexport async function fetchAllPrivacyCenters(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<PrivacyCenter[]> {\n const { logger } = options;\n const deployedPrivacyCenterUrl = await fetchPrivacyCenterUrl(client, { logger });\n const {\n privacyCenter: { themeStr, ...rest },\n } = await makeGraphQLRequest<{\n /** Privacy centers */\n privacyCenter: Omit<PrivacyCenter, 'theme'> & {\n /** Theme string */\n themeStr: string;\n };\n }>(client, PRIVACY_CENTER, {\n variables: { url: deployedPrivacyCenterUrl },\n logger,\n });\n\n return [\n {\n ...rest,\n theme: JSON.parse(themeStr),\n },\n ];\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// orderBy: [\n// { field: createdAt, direction: ASC }\n// { field: name, direction: ASC }\n// ]\nexport const PROCESSING_PURPOSE_SUB_CATEGORIES = gql`\n query TranscendCliProcessingPurposeSubCategories($first: Int!, $offset: Int!) {\n processingPurposeSubCategories(\n first: $first\n offset: $offset\n isExportCsv: true\n useMaster: false\n ) {\n nodes {\n id\n name\n purpose\n description\n teams {\n name\n }\n owners {\n email\n }\n attributeValues {\n attributeKey {\n name\n }\n name\n }\n }\n }\n }\n`;\n\nexport const CREATE_PROCESSING_PURPOSE_SUB_CATEGORY = gql`\n mutation TranscendCliCreateProcessingPurposeSubCategory(\n $input: CreateProcessingPurposeCategoryInput!\n ) {\n createProcessingPurposeSubCategory(input: $input) {\n processingPurposeSubCategory {\n id\n name\n purpose\n }\n }\n }\n`;\n\nexport const UPDATE_PROCESSING_PURPOSE_SUB_CATEGORIES = gql`\n mutation TranscendCliUpdateProcessingPurposeSubCategories(\n $input: UpdateProcessingPurposeSubCategoriesInput!\n ) {\n updateProcessingPurposeSubCategories(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { ProcessingPurpose } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PROCESSING_PURPOSE_SUB_CATEGORIES } from './gqls/processingPurpose.js';\n\nexport interface ProcessingPurposeSubCategory {\n /** ID of processing purpose */\n id: string;\n /** Name of processing purpose */\n name: string;\n /** Type of processing purpose */\n purpose: ProcessingPurpose;\n /** Description of processing purpose */\n description?: string;\n /** Assigned teams */\n teams: {\n /** Team name */\n name: string;\n }[];\n /** Assigned owners */\n owners: {\n /** Email */\n email: string;\n }[];\n /** Custom fields */\n attributeValues: {\n /** Name of attribute value */\n name: string;\n /** Attribute key that the value represents */\n attributeKey: {\n /** Name of attribute team */\n name: string;\n };\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all processingPurposeSubCategories in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All processingPurposeSubCategories in the organization\n */\nexport async function fetchAllProcessingPurposes(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<ProcessingPurposeSubCategory[]> {\n const processingPurposeSubCategories: ProcessingPurposeSubCategory[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n processingPurposeSubCategories: { nodes },\n } = await makeGraphQLRequest<{\n /** DataCategories */\n processingPurposeSubCategories: {\n /** List */\n nodes: ProcessingPurposeSubCategory[];\n };\n }>(client, PROCESSING_PURPOSE_SUB_CATEGORIES, {\n variables: { first: PAGE_SIZE, offset },\n logger: options.logger,\n });\n processingPurposeSubCategories.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return processingPurposeSubCategories.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n/** Preference topic title translation */\nexport interface TranscendPreferenceTopicTitle {\n /** Translated description */\n description: string;\n}\n\n/** Preference topic linked to a purpose */\nexport interface TranscendPreferenceTopicGql {\n /** Topic ID */\n id: string;\n /** Topic slug */\n slug: string;\n /** Topic title with translations */\n title: TranscendPreferenceTopicTitle;\n /** Display color */\n color: string;\n}\n\n/** Data silo (integration) mapped to a purpose */\nexport interface TranscendMappedDataSiloGql {\n /** Data silo ID */\n id: string;\n /** Data silo display title */\n title: string;\n /** Data silo type */\n type: string;\n}\n\n/** Tracking purpose returned by the PURPOSES query */\nexport interface TranscendPurposeGql {\n /** Purpose ID */\n id: string;\n /** Purpose display name */\n name: string;\n /** Purpose description */\n description: string | null;\n /** Default consent state */\n defaultConsent: string;\n /** Purpose slug */\n trackingType: string;\n /** Whether the purpose is user-configurable */\n configurable: boolean;\n /** Whether the purpose is essential (non-optional) */\n essential: boolean;\n /** Whether the purpose appears in the consent manager UI */\n showInConsentManager: boolean;\n /** Whether the purpose is currently active */\n isActive: boolean;\n /** Display ordering weight */\n displayOrder: number;\n /** Signals that trigger automatic opt-out (e.g. GPC) */\n optOutSignals: string[];\n /** Soft-deletion timestamp, null if active */\n deletedAt: string | null;\n /** Authentication level required */\n authLevel: string;\n /** Whether the purpose appears in the privacy center */\n showInPrivacyCenter: boolean;\n /** Localized display title */\n title: string | null;\n /** Linked preference topics */\n preferenceTopics: TranscendPreferenceTopicGql[];\n /** Number of data points tracked under this purpose */\n purposeDataPointCount: number;\n /** Number of preference topic option value data points */\n preferenceTopicOptionValueDataPointCount: number;\n /** Data silos mapped to this purpose */\n mappedDataSilos: TranscendMappedDataSiloGql[];\n}\n\n/** Full response from the PURPOSES query */\nexport interface TranscendCliPurposesResponse {\n /** Purposes result */\n purposes: {\n /** List of purpose nodes */\n nodes: TranscendPurposeGql[];\n /** Total count of purposes */\n totalCount: number;\n };\n}\n\nexport const PURPOSES = gql`\n query TranscendCliPurposes($first: Int!) {\n purposes(first: $first) {\n nodes {\n id\n name\n description\n defaultConsent\n trackingType\n configurable\n essential\n showInConsentManager\n isActive\n displayOrder\n optOutSignals\n deletedAt\n authLevel\n showInPrivacyCenter\n title\n preferenceTopics {\n id\n slug\n title {\n description\n }\n color\n }\n purposeDataPointCount\n preferenceTopicOptionValueDataPointCount\n mappedDataSilos {\n id\n title\n type\n }\n }\n totalCount\n }\n }\n`;\n","import { gql } from 'graphql-request';\n\n// ---- Shared partition types ----\n\n/** Consent partition node */\nexport interface TranscendConsentPartitionGql {\n /** Partition ID */\n id: string;\n /** Partition name */\n name: string;\n /** Partition key */\n partition: string;\n}\n\n// ---- CONSENT_PARTITIONS query ----\n\n/** Full response from the CONSENT_PARTITIONS query */\nexport interface TranscendCliConsentPartitionsResponse {\n /** Partitions result */\n consentPartitions: {\n /** List of partition nodes */\n nodes: TranscendConsentPartitionGql[];\n };\n}\n\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// useMaster: false\n// isExportCsv: true\nexport const CONSENT_PARTITIONS = gql`\n query TranscendCliConsentPartitions($first: Int!, $offset: Int!) {\n consentPartitions(first: $first, offset: $offset) {\n nodes {\n id\n name\n partition\n }\n }\n }\n`;\n\n// ---- CREATE_CONSENT_PARTITION mutation ----\n\n/** Full response from the CREATE_CONSENT_PARTITION mutation */\nexport interface TranscendCliCreateConsentPartitionResponse {\n /** Mutation result */\n createConsentPartition: {\n /** Client mutation ID */\n clientMutationId: string | null;\n };\n}\n\nexport const CREATE_CONSENT_PARTITION = gql`\n mutation TranscendCliCreateConsentPartition($input: CreateConsentPartitionInput!) {\n createConsentPartition(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { gql } from 'graphql-request';\n\n/** Stats counts returned by COOKIE_STATS and DATA_FLOW_STATS */\nexport interface TranscendTrackerStatsGql {\n /** Number of live (approved) items */\n liveCount: number;\n /** Number of items needing review */\n needReviewCount: number;\n /** Number of junked items */\n junkCount: number;\n}\n\n/** Full response from the COOKIE_STATS query */\nexport interface TranscendCliCookieStatsResponse {\n /** Cookie stats result */\n cookieStats: TranscendTrackerStatsGql;\n}\n\nexport const COOKIE_STATS = gql`\n query TranscendCliCookieStats($input: AirgapBundleInput!) {\n cookieStats(input: $input) {\n liveCount\n needReviewCount\n junkCount\n }\n }\n`;\n\n/** Full response from the DATA_FLOW_STATS query */\nexport interface TranscendCliDataFlowStatsResponse {\n /** Data flow stats result */\n dataFlowStats: TranscendTrackerStatsGql;\n}\n\nexport const DATA_FLOW_STATS = gql`\n query TranscendCliDataFlowStats($input: AirgapBundleInput!) {\n dataFlowStats(input: $input) {\n liveCount\n needReviewCount\n junkCount\n }\n }\n`;\n","import { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { difference } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchConsentManagerId } from './fetchConsentManagerId.js';\nimport {\n CONSENT_PARTITIONS,\n CREATE_CONSENT_PARTITION,\n type TranscendConsentPartitionGql,\n type TranscendCliConsentPartitionsResponse,\n} from './gqls/partitions.js';\n\nconst PAGE_SIZE = 50;\n\nexport interface PartitionInput {\n /** Name of partition */\n name: string;\n /** Value of partition, cannot be pushed, can only be pulled */\n partition?: string;\n}\n\n/**\n * Fetch the list of partitions\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Partition list\n */\nexport async function fetchPartitions(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<TranscendConsentPartitionGql[]> {\n const { logger = NOOP_LOGGER } = options;\n const partitions: TranscendConsentPartitionGql[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n consentPartitions: { nodes },\n } = await makeGraphQLRequest<TranscendCliConsentPartitionsResponse>(\n client,\n CONSENT_PARTITIONS,\n {\n variables: { first: PAGE_SIZE, offset },\n logger,\n },\n );\n partitions.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return partitions.sort((a, b) => a.name.localeCompare(b.name));\n}\n\n/**\n * Sync the consent partitions\n *\n * @param client - GraphQL client\n * @param partitionInputs - The partition inputs\n * @param options - Options\n * @returns True on success\n */\nexport async function syncPartitions(\n client: GraphQLClient,\n partitionInputs: PartitionInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n const airgapBundleId = await fetchConsentManagerId(client, { logger });\n let encounteredError = false;\n const partitions = await fetchPartitions(client, { logger });\n const newPartitionNames = difference(\n partitionInputs.map(({ name }) => name),\n partitions.map(({ name }) => name),\n );\n await mapSeries(newPartitionNames, async (name) => {\n try {\n await makeGraphQLRequest(client, CREATE_CONSENT_PARTITION, {\n variables: {\n input: {\n id: airgapBundleId,\n name,\n },\n },\n logger,\n });\n logger.info(`Successfully created consent partition: ${name}!`);\n } catch (err) {\n logger.error(`Failed to create consent partition: ${name}! - ${(err as Error).message}`);\n encounteredError = true;\n }\n });\n return !encounteredError;\n}\n","import { InitialViewState, OnConsentExpiry, BrowserLanguage } from '@transcend-io/airgap.js-types';\nimport {\n ConsentBundleType,\n ConsentPrecedenceOption,\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n RegionsOperator,\n UnknownRequestPolicy,\n TelemetryPartitionStrategy,\n SignedIabAgreementOption,\n BrowserTimeZone,\n} from '@transcend-io/privacy-types';\nimport { map, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllPurposes } from '../preference-management/fetchAllPurposes.js';\nimport { fetchConsentManagerId, fetchConsentManagerExperiences } from './fetchConsentManagerId.js';\nimport { fetchPrivacyCenterId } from './fetchPrivacyCenterId.js';\nimport {\n UPDATE_CONSENT_MANAGER_DOMAINS,\n CREATE_CONSENT_MANAGER,\n UPDATE_LOAD_OPTIONS,\n UPDATE_CONSENT_MANAGER_PARTITION,\n UPDATE_CONSENT_MANAGER_VERSION,\n TOGGLE_TELEMETRY_PARTITION_STRATEGY,\n TOGGLE_UNKNOWN_COOKIE_POLICY,\n TOGGLE_CONSENT_PRECEDENCE,\n TOGGLE_UNKNOWN_REQUEST_POLICY,\n UPDATE_CONSENT_MANAGER_THEME,\n} from './gqls/consentManager.js';\nimport { UPDATE_CONSENT_EXPERIENCE, CREATE_CONSENT_EXPERIENCE } from './gqls/experiences.js';\nimport { fetchPartitions } from './syncPartitions.js';\n\nconst PURPOSES_LINK = 'https://app.transcend.io/consent-manager/regional-experiences/purposes';\n\nexport interface ConsentManageExperienceInput {\n /** Name of experience */\n name: string;\n /** Display name of experience */\n displayName?: string;\n /** Regions that define this regional experience */\n regions?: {\n /** Country */\n country?: IsoCountryCode;\n /** Country subdivision */\n countrySubDivision?: IsoCountrySubdivisionCode;\n }[];\n /** How to handle consent expiry */\n onConsentExpiry?: OnConsentExpiry;\n /** Consent expiration value */\n consentExpiry?: number;\n /** In vs not in operator */\n operator?: RegionsOperator;\n /** Priority of experience */\n displayPriority?: number;\n /** View state to prompt when auto prompting is enabled */\n viewState?: InitialViewState;\n /** Purposes that can be opted out of in a particular experience */\n purposes?: {\n /** Slug of purpose */\n trackingType: string;\n }[];\n /** Purposes that are opted out by default in a particular experience */\n optedOutPurposes?: {\n /** Slug of purpose */\n trackingType: string;\n }[];\n /** Browser languages that define this regional experience */\n browserLanguages?: BrowserLanguage[];\n /** Browser time zones that define this regional experience */\n browserTimeZones?: BrowserTimeZone[];\n}\n\nexport interface ConsentManagerInput {\n /** Airgap version */\n version?: string;\n /** Bundle URLs per bundle type */\n bundleUrls?: Partial<Record<ConsentBundleType, string>>;\n /** The consent manager domains */\n domains?: string[];\n /** Key used to partition consent records */\n partition?: string;\n /** Precedence of signals vs user input */\n consentPrecedence?: ConsentPrecedenceOption;\n /** The consent manager unknown request policy */\n unknownRequestPolicy?: UnknownRequestPolicy;\n /** The consent manager unknown cookie policy */\n unknownCookiePolicy?: UnknownRequestPolicy;\n /** The XDI sync endpoint */\n syncEndpoint?: string;\n /** The telemetry partitioning strategy */\n telemetryPartitioning?: TelemetryPartitionStrategy;\n /** Whether the site owner has signed the IAB agreement */\n signedIabAgreement?: SignedIabAgreementOption;\n /** Regional experience configurations */\n experiences?: ConsentManageExperienceInput[];\n /** Theme configuration */\n theme?: {\n /** Primary color */\n primaryColor?: string;\n /** Font color */\n fontColor?: string;\n /** Privacy policy URL */\n privacyPolicy?: string;\n /** Auto-prompt setting */\n prompt?: number;\n };\n /** The Shared XDI host sync groups config (JSON) */\n syncGroups?: string;\n}\n\n/**\n * Sync consent manager experiences up to Transcend\n *\n * @param client - GraphQL client\n * @param experiences - The experience inputs\n * @param options - Options\n */\nexport async function syncConsentManagerExperiences(\n client: GraphQLClient,\n experiences: ConsentManageExperienceInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n const { logger = NOOP_LOGGER } = options;\n\n const existingExperiences = await fetchConsentManagerExperiences(client, {\n logger,\n });\n const experienceLookup = keyBy(existingExperiences, 'name');\n\n const purposes = await fetchAllPurposes(client, { logger });\n const purposeLookup = keyBy(purposes, 'trackingType');\n\n await map(\n experiences,\n async (exp, ind) => {\n const purposeIds = exp.purposes?.map((purpose, ind2) => {\n const existingPurpose = purposeLookup[purpose.trackingType];\n if (!existingPurpose) {\n throw new Error(\n `Invalid purpose trackingType provided at consentManager.experiences[${ind}].purposes[${ind2}]: ` +\n `${purpose.trackingType}. See list of valid purposes ${PURPOSES_LINK}`,\n );\n }\n return existingPurpose.id;\n });\n const optedOutPurposeIds = exp.optedOutPurposes?.map((purpose, ind2) => {\n const existingPurpose = purposeLookup[purpose.trackingType];\n if (!existingPurpose) {\n throw new Error(\n `Invalid purpose trackingType provided at consentManager.experiences[${ind}].optedOutPurposes[${ind2}]: ` +\n `${purpose.trackingType}. See list of valid purposes ${PURPOSES_LINK}`,\n );\n }\n return existingPurpose.id;\n });\n\n const existingExperience = experienceLookup[exp.name];\n if (existingExperience) {\n await makeGraphQLRequest(client, UPDATE_CONSENT_EXPERIENCE, {\n variables: {\n input: {\n id: existingExperience.id,\n name: exp.displayName,\n regions: exp.regions,\n operator: exp.operator,\n onConsentExpiry: exp.onConsentExpiry,\n consentExpiry: exp.consentExpiry,\n displayPriority:\n exp.displayPriority !== existingExperience.displayPriority\n ? exp.displayPriority\n : undefined,\n viewState: exp.viewState,\n purposes: purposeIds,\n optedOutPurposes: optedOutPurposeIds,\n browserLanguages: exp.browserLanguages,\n browserTimeZones: exp.browserTimeZones,\n },\n },\n logger,\n });\n logger.info(`Successfully synced consent experience \"${exp.name}\"!`);\n } else {\n await makeGraphQLRequest(client, CREATE_CONSENT_EXPERIENCE, {\n variables: {\n input: {\n name: exp.name,\n displayName: exp.displayName,\n regions: exp.regions,\n operator: exp.operator,\n onConsentExpiry: exp.onConsentExpiry || OnConsentExpiry.Prompt,\n consentExpiry: exp.consentExpiry,\n displayPriority: exp.displayPriority,\n viewState: exp.viewState || InitialViewState.Hidden,\n purposes: purposeIds || [],\n optedOutPurposes: optedOutPurposeIds || [],\n browserLanguages: exp.browserLanguages,\n browserTimeZones: exp.browserTimeZones,\n },\n },\n logger,\n });\n logger.info(`Successfully created consent experience \"${exp.name}\"!`);\n }\n },\n {\n concurrency: 10,\n },\n );\n}\n\n/**\n * Sync the consent manager\n *\n * @param client - GraphQL client\n * @param consentManager - The consent manager input\n * @param options - Options\n */\nexport async function syncConsentManager(\n client: GraphQLClient,\n consentManager: ConsentManagerInput,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n const { logger = NOOP_LOGGER } = options;\n let airgapBundleId: string;\n\n try {\n airgapBundleId = await fetchConsentManagerId(client, {\n logger,\n maxRequests: 1,\n });\n } catch (err) {\n // TODO: https://transcend.height.app/T-23778\n if ((err as Error).message.includes('AirgapBundle not found')) {\n const privacyCenterId = await fetchPrivacyCenterId(client, {\n logger,\n });\n\n const { createConsentManager } = await makeGraphQLRequest<{\n /** Create consent manager */\n createConsentManager: {\n /** Consent manager */\n consentManager: {\n /** ID */\n id: string;\n };\n };\n }>(client, CREATE_CONSENT_MANAGER, {\n variables: { privacyCenterId },\n logger,\n });\n airgapBundleId = createConsentManager.consentManager.id;\n } else {\n throw err;\n }\n }\n\n if (consentManager.domains) {\n await makeGraphQLRequest(client, UPDATE_CONSENT_MANAGER_DOMAINS, {\n variables: { domains: consentManager.domains, airgapBundleId },\n logger,\n });\n }\n\n if (consentManager.partition) {\n const partitions = await fetchPartitions(client, { logger });\n const partitionToUpdate = partitions.find((part) => part.name === consentManager.partition);\n if (!partitionToUpdate) {\n throw new Error(\n `Partition \"${consentManager.partition}\" not found. Please create the partition first.`,\n );\n }\n await makeGraphQLRequest(client, UPDATE_CONSENT_MANAGER_PARTITION, {\n variables: { partitionId: partitionToUpdate.id, airgapBundleId },\n logger,\n });\n }\n\n if (consentManager.version) {\n await makeGraphQLRequest(client, UPDATE_CONSENT_MANAGER_VERSION, {\n variables: { airgapBundleId, version: consentManager.version },\n logger,\n });\n }\n\n if (consentManager.signedIabAgreement) {\n await makeGraphQLRequest(client, UPDATE_LOAD_OPTIONS, {\n variables: {\n input: {\n id: airgapBundleId,\n ...(consentManager.signedIabAgreement\n ? { signedIabAgreement: consentManager.signedIabAgreement }\n : {}),\n },\n },\n logger,\n });\n }\n\n if (consentManager.unknownRequestPolicy) {\n await makeGraphQLRequest(client, TOGGLE_UNKNOWN_REQUEST_POLICY, {\n variables: {\n input: {\n id: airgapBundleId,\n unknownRequestPolicy: consentManager.unknownRequestPolicy,\n },\n },\n logger,\n });\n }\n\n if (consentManager.unknownRequestPolicy) {\n await makeGraphQLRequest(client, TOGGLE_UNKNOWN_COOKIE_POLICY, {\n variables: {\n input: {\n id: airgapBundleId,\n unknownCookiePolicy: consentManager.unknownCookiePolicy,\n },\n },\n logger,\n });\n }\n\n if (consentManager.telemetryPartitioning) {\n await makeGraphQLRequest(client, TOGGLE_TELEMETRY_PARTITION_STRATEGY, {\n variables: {\n input: {\n id: airgapBundleId,\n strategy: consentManager.telemetryPartitioning,\n },\n },\n logger,\n });\n }\n\n if (consentManager.consentPrecedence) {\n await makeGraphQLRequest(client, TOGGLE_CONSENT_PRECEDENCE, {\n variables: {\n input: {\n id: airgapBundleId,\n consentPrecedence: consentManager.consentPrecedence,\n },\n },\n logger,\n });\n }\n\n if (consentManager.experiences) {\n await syncConsentManagerExperiences(client, consentManager.experiences, {\n logger,\n });\n }\n\n if (consentManager.theme) {\n await makeGraphQLRequest(client, UPDATE_CONSENT_MANAGER_THEME, {\n variables: {\n input: {\n airgapBundleId,\n ...consentManager.theme,\n },\n },\n logger,\n });\n }\n\n // TODO: https://transcend.height.app/T-23875\n // syncEndpoint: string;\n // TODO: https://transcend.height.app/T-23919\n // syncGroups: string;\n}\n","import { ConsentTrackerStatus } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchConsentManagerId } from './fetchConsentManagerId.js';\nimport { UPDATE_OR_CREATE_COOKIES } from './gqls/cookies.js';\n\nexport interface CookieInput {\n /** Name of cookie */\n name: string;\n /** Whether or not the cookie is a regular expression */\n isRegex?: boolean;\n /** Description of cookie */\n description?: string;\n /** The tracking purposes that are required to be opted in for this cookie */\n trackingPurposes?: string[];\n /** Name of the consent service attached */\n service?: string;\n /** Status of the tracker (approved vs triage) */\n status?: ConsentTrackerStatus;\n /** Email addresses of owners */\n owners?: string[];\n /** Names of teams responsible for managing this cookie */\n teams?: string[];\n /** Attribute key-value pairs */\n attributes?: {\n /** Attribute key */\n key: string;\n /** Attribute values */\n values: string[];\n }[];\n}\n\nconst MAX_PAGE_SIZE = 100;\n\n/**\n * Update or create cookies\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateOrCreateCookies(\n client: GraphQLClient,\n options: {\n /** List of cookie inputs */\n input: CookieInput[];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: cookies, logger = NOOP_LOGGER } = options;\n const airgapBundleId = await fetchConsentManagerId(client, { logger });\n\n await mapSeries(chunk(cookies, MAX_PAGE_SIZE), async (page) => {\n await makeGraphQLRequest(client, UPDATE_OR_CREATE_COOKIES, {\n variables: {\n airgapBundleId,\n cookies: page.map((cookie) => ({\n name: cookie.name,\n trackingPurposes:\n cookie.trackingPurposes && cookie.trackingPurposes.length > 0\n ? cookie.trackingPurposes\n : undefined,\n description: cookie.description,\n service: cookie.service,\n status: cookie.status,\n attributes: cookie.attributes,\n isRegex: cookie.isRegex,\n })),\n },\n logger,\n });\n });\n}\n\n/**\n * Sync the set of cookies into the product\n *\n * @param client - GraphQL client\n * @param cookies - Cookies to sync\n * @param options - Options\n * @returns True upon success, false upon failure\n */\nexport async function syncCookies(\n client: GraphQLClient,\n cookies: CookieInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${cookies.length}\" cookies...`);\n\n const notUnique = cookies.filter(\n (cookie) =>\n cookies.filter((cook) => cookie.name === cook.name && cookie.isRegex === cook.isRegex)\n .length > 1,\n );\n if (notUnique.length > 0) {\n throw new Error(\n `Failed to upload cookies as there were non-unique entries found: ${notUnique\n .map(({ name }) => name)\n .join(',')}`,\n );\n }\n\n try {\n logger.info(`Upserting \"${cookies.length}\" new cookies...`);\n await updateOrCreateCookies(client, { input: cookies, logger });\n logger.info(`Successfully synced ${cookies.length} cookies!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create cookies! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import { ConsentTrackerStatus, DataFlowScope } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllDataFlows } from './fetchAllDataFlows.js';\nimport { fetchConsentManagerId } from './fetchConsentManagerId.js';\nimport { CREATE_DATA_FLOWS, UPDATE_DATA_FLOWS } from './gqls/dataFlows.js';\n\n/** Attribute key-value pair for a data flow */\nexport interface DataFlowAttributeInput {\n /** Attribute key */\n key: string;\n /** Attribute values */\n values: string[];\n}\n\n/**\n * Input to define a data flow for sync\n *\n * @see https://app.transcend.io/consent-manager/data-flows/approved\n */\nexport interface DataFlowInput {\n /** Value of data flow */\n value: string;\n /** Type of data flow */\n type: DataFlowScope;\n /** Description of data flow */\n description?: string;\n /** The tracking purposes that are required to be opted in for this data flow */\n trackingPurposes?: string[];\n /** Name of the consent service attached */\n service?: string;\n /** Status of the tracker (approved vs triage) */\n status?: ConsentTrackerStatus;\n /** Email addresses of owners */\n owners?: string[];\n /** Names of teams responsible for managing this data flow */\n teams?: string[];\n /** Attribute key-value pairs */\n attributes?: DataFlowAttributeInput[];\n}\n\nconst MAX_PAGE_SIZE = 100;\n\n/**\n * Update data flows that already existed\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateDataFlows(\n client: GraphQLClient,\n options: {\n /** [DataFlowInput, Data Flow ID] mappings to update */\n input: [DataFlowInput, string][];\n /** Classify service if missing */\n classifyService?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: dataFlows, classifyService = false, logger = NOOP_LOGGER } = options;\n const airgapBundleId = await fetchConsentManagerId(client, { logger });\n\n // TODO: https://transcend.height.app/T-19841 - add with custom purposes\n // const purposes = await fetchAllPurposes(client);\n // const purposeNameToId = keyBy(purposes, 'name');\n\n await mapSeries(chunk(dataFlows, MAX_PAGE_SIZE), async (page) => {\n await makeGraphQLRequest(client, UPDATE_DATA_FLOWS, {\n variables: {\n airgapBundleId,\n dataFlows: page.map(([flow, id]) => ({\n id,\n value: flow.value,\n type: flow.type,\n trackingType:\n flow.trackingPurposes && flow.trackingPurposes.length > 0\n ? flow.trackingPurposes\n : undefined,\n // TODO: https://transcend.height.app/T-19841 - add with custom purposes\n // purposeIds: flow.trackingPurposes\n // ? flow.trackingPurposes\n // .filter((purpose) => purpose !== 'Unknown')\n // .map((purpose) => purposeNameToId[purpose].id)\n // : undefined,\n description: flow.description,\n service: flow.service,\n status: flow.status,\n attributes: flow.attributes,\n // TODO: https://transcend.height.app/T-23718\n // owners,\n // teams,\n })),\n classifyService,\n },\n logger,\n });\n });\n}\n\n/**\n * Create new data flows\n *\n * @param client - GraphQL client\n * @param dataFlowInputs - List of data flows to create\n * @param options - Options\n */\nexport async function createDataFlows(\n client: GraphQLClient,\n options: {\n /** Data flow inputs to create */\n input: DataFlowInput[];\n /** Classify service if missing */\n classifyService?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: dataFlowInputs, classifyService = false, logger = NOOP_LOGGER } = options;\n const airgapBundleId = await fetchConsentManagerId(client, { logger });\n\n // TODO: https://transcend.height.app/T-19841 - add with custom purposes\n // const purposes = await fetchAllPurposes(client);\n // const purposeNameToId = keyBy(purposes, 'name');\n\n await mapSeries(chunk(dataFlowInputs, MAX_PAGE_SIZE), async (page) => {\n await makeGraphQLRequest(client, CREATE_DATA_FLOWS, {\n variables: {\n airgapBundleId,\n dataFlows: page.map((flow) => ({\n value: flow.value,\n type: flow.type,\n trackingType:\n flow.trackingPurposes && flow.trackingPurposes.length > 0\n ? flow.trackingPurposes\n : undefined,\n // TODO: https://transcend.height.app/T-19841 - add with custom purposes\n // purposeIds: flow.trackingPurposes\n // ? flow.trackingPurposes\n // .filter((purpose) => purpose !== 'Unknown')\n // .map((purpose) => purposeNameToId[purpose].id)\n // : undefined,\n description: flow.description,\n service: flow.service,\n status: flow.status,\n attributes: flow.attributes,\n // TODO: https://transcend.height.app/T-23718\n // owners,\n // teams,\n })),\n classifyService,\n },\n logger,\n });\n });\n}\n\n/**\n * Sync data flow configurations into Transcend\n *\n * @param client - GraphQL client\n * @param dataFlows - The data flows to upload\n * @param options - Options\n * @returns True if the command ran successfully, returns false if an error occurred\n */\nexport async function syncDataFlows(\n client: GraphQLClient,\n dataFlows: DataFlowInput[],\n options: {\n /** When true, auto classify the service based on the data flow value */\n classifyService?: boolean;\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { classifyService = false, logger = NOOP_LOGGER } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${dataFlows.length}\" data flows...`);\n\n const notUnique = dataFlows.filter(\n (dataFlow) =>\n dataFlows.filter((flow) => dataFlow.value === flow.value && dataFlow.type === flow.type)\n .length > 1,\n );\n\n if (notUnique.length > 0) {\n throw new Error(\n `Failed to upload data flows as there were non-unique entries found: ${notUnique\n .map(({ value }) => value)\n .join(',')}`,\n );\n }\n\n logger.info('Fetching data flows...');\n const [existingLiveDataFlows, existingInReviewDataFlows] = await Promise.all([\n fetchAllDataFlows(client, {\n logger,\n filterBy: { status: ConsentTrackerStatus.Live },\n }),\n fetchAllDataFlows(client, {\n logger,\n filterBy: { status: ConsentTrackerStatus.NeedsReview },\n }),\n ]);\n const allDataFlows = [...existingLiveDataFlows, ...existingInReviewDataFlows];\n\n const mapDataFlowsToExisting = dataFlows.map((dataFlow) => [\n dataFlow,\n allDataFlows.find((flow) => dataFlow.value === flow.value && dataFlow.type === flow.type)?.id,\n ]);\n\n const newDataFlows = mapDataFlowsToExisting\n .filter(([, existing]) => !existing)\n .map(([flow]) => flow as DataFlowInput);\n try {\n logger.info(`Creating \"${newDataFlows.length}\" new data flows...`);\n await createDataFlows(client, { input: newDataFlows, classifyService, logger });\n logger.info(`Successfully synced ${newDataFlows.length} data flows!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create data flows! - ${(err as Error).message}`);\n }\n\n const existingDataFlows = mapDataFlowsToExisting.filter(\n (x): x is [DataFlowInput, string] => !!x[1],\n );\n try {\n logger.info(`Updating \"${existingDataFlows.length}\" data flows...`);\n await updateDataFlows(client, { input: existingDataFlows, classifyService, logger });\n logger.info(`Successfully updated \"${existingDataFlows.length}\" data flows!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to update data flows! - ${(err as Error).message}`);\n }\n\n logger.info(`Synced \"${dataFlows.length}\" data flows!`);\n\n return !encounteredError;\n}\n","import type { LocaleValue } from '@transcend-io/internationalization';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk, keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllPolicies } from './fetchAllPolicies.js';\nimport { fetchPrivacyCenterId } from './fetchPrivacyCenterId.js';\nimport { UPDATE_POLICIES } from './gqls/policy.js';\n\nexport interface PolicyInput {\n /** The title of the policy */\n title: string;\n /** Effective date of policy */\n effectiveOn?: string;\n /** Whether or not to disable the effective date */\n disableEffectiveOn?: boolean;\n /** Content of the policy */\n content?: string;\n /** The languages for which the policy is disabled for */\n disabledLocales?: LocaleValue[];\n}\n\nconst MAX_PAGE_SIZE = 100;\n\n/**\n * Update or create policies\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updatePolicies(\n client: GraphQLClient,\n options: {\n /** [PolicyInput, policyId] list */\n input: [PolicyInput, string | undefined][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: policyInputs, logger = NOOP_LOGGER } = options;\n const privacyCenterId = await fetchPrivacyCenterId(client, { logger });\n\n await mapSeries(chunk(policyInputs, MAX_PAGE_SIZE), async (page) => {\n await makeGraphQLRequest(client, UPDATE_POLICIES, {\n variables: {\n privacyCenterId,\n policies: page.map(([policy, policyId]) => ({\n id: policyId,\n title: policy.title,\n disableEffectiveOn: policy.disableEffectiveOn,\n disabledLocales: policy.disabledLocales,\n ...(policy.effectiveOn || policy.content\n ? {\n version: {\n ...(policy.effectiveOn ? { effectiveOn: policy.effectiveOn } : {}),\n ...(policy.content\n ? {\n content: {\n defaultMessage: policy.content,\n },\n }\n : {}),\n },\n }\n : {}),\n })),\n },\n logger,\n });\n });\n}\n\n/**\n * Sync the set of policies from the YML interface into the product\n *\n * @param client - GraphQL client\n * @param policies - policies to sync\n * @param options - Options\n * @returns True upon success, false upon failure\n */\nexport async function syncPolicies(\n client: GraphQLClient,\n policies: PolicyInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${policies.length}\" policies...`);\n\n const notUnique = policies.filter(\n (policy) => policies.filter((pol) => policy.title === pol.title).length > 1,\n );\n if (notUnique.length > 0) {\n throw new Error(\n `Failed to upload policies as there were non-unique entries found: ${notUnique\n .map(({ title }) => title)\n .join(',')}`,\n );\n }\n\n const existingPolicies = await fetchAllPolicies(client, { logger });\n const policiesById = keyBy(existingPolicies, ({ title }) => title.defaultMessage);\n\n try {\n logger.info(`Upserting \"${policies.length}\" new policies...`);\n await updatePolicies(client, {\n input: policies.map((policy) => [policy, policiesById[policy.title]?.id]),\n logger,\n });\n logger.info(`Successfully synced ${policies.length} policies!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create policies! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import type { LocaleValue } from '@transcend-io/internationalization';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchPrivacyCenterId } from './fetchPrivacyCenterId.js';\nimport { UPDATE_PRIVACY_CENTER } from './gqls/privacyCenter.js';\n\nexport interface PrivacyCenterInput {\n /** Whether or not the entire privacy center is enabled or disabled */\n isDisabled?: boolean;\n /** Whether or not to show the privacy requests button */\n showPrivacyRequestButton?: boolean;\n /** Whether or not to show the data practices page */\n showDataPractices?: boolean;\n /** Whether or not to show the policies page */\n showPolicies?: boolean;\n /** Whether or not to show the tracking technologies page */\n showTrackingTechnologies?: boolean;\n /** Whether or not to show the cookies on the tracking technologies page */\n showCookies?: boolean;\n /** Whether or not to show the data flows on the tracking technologies page */\n showDataFlows?: boolean;\n /** Whether or not to show the consent manager opt out options on the tracking technologies page */\n showConsentManager?: boolean;\n /** Whether or not to show the manage your privacy page */\n showManageYourPrivacy?: boolean;\n /** Whether or not to show the marketing preferences page */\n showMarketingPreferences?: boolean;\n /** What languages are supported for the privacy center */\n locales?: LocaleValue[];\n /** The default locale for the privacy center */\n defaultLocale?: LocaleValue;\n /** Whether or not to prefer the browser default locale */\n preferBrowserDefaultLocale?: boolean;\n /** The support email address */\n supportEmail?: string;\n /** The reply-to email address */\n replyToEmail?: string;\n /** Whether or not to send emails from a no reply email */\n useNoReplyEmailAddress?: boolean;\n /** Whether or not to use a custom email domain */\n useCustomEmailDomain?: boolean;\n /** Whether or not to transcend access requests from JSON to CSV */\n transformAccessReportJsonToCsv?: boolean;\n /** The theme object of colors to display on the privacy center */\n theme?: {\n /** The theme colors */\n colors?: Record<string, string | undefined>;\n /** Styles to apply to components */\n componentStyles?: Record<string, unknown>;\n /** Override styles */\n textStyles?: Record<string, unknown>;\n };\n}\n\n/**\n * Sync the privacy center\n *\n * @param client - GraphQL client\n * @param privacyCenter - The privacy center input\n * @param options - Options\n * @returns Whether the privacy center was synced successfully\n */\nexport async function syncPrivacyCenter(\n client: GraphQLClient,\n privacyCenter: PrivacyCenterInput,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n let encounteredError = false;\n logger.info('Syncing privacy center...');\n\n const privacyCenterId = await fetchPrivacyCenterId(client, { logger });\n\n try {\n await makeGraphQLRequest(client, UPDATE_PRIVACY_CENTER, {\n variables: {\n input: {\n privacyCenterId,\n transformAccessReportJsonToCsv: privacyCenter.transformAccessReportJsonToCsv,\n useCustomEmailDomain: privacyCenter.useCustomEmailDomain,\n useNoReplyEmailAddress: privacyCenter.useNoReplyEmailAddress,\n replyToEmail: privacyCenter.replyToEmail,\n supportEmail: privacyCenter.supportEmail,\n preferBrowserDefaultLocale: privacyCenter.preferBrowserDefaultLocale,\n defaultLocale: privacyCenter.defaultLocale,\n locales: privacyCenter.locales,\n showMarketingPreferences: privacyCenter.showMarketingPreferences,\n showManageYourPrivacy: privacyCenter.showManageYourPrivacy,\n showPolicies: privacyCenter.showPolicies,\n showConsentManager: privacyCenter.showConsentManager,\n showDataFlows: privacyCenter.showDataFlows,\n showCookies: privacyCenter.showCookies,\n showTrackingTechnologies: privacyCenter.showTrackingTechnologies,\n showPrivacyRequestButton: privacyCenter.showPrivacyRequestButton,\n isDisabled: privacyCenter.isDisabled,\n ...(privacyCenter.theme\n ? {\n colorPalette: privacyCenter.theme.colors,\n componentStyles: privacyCenter.theme.componentStyles,\n textStyles: privacyCenter.theme.textStyles,\n }\n : {}),\n },\n },\n logger,\n });\n logger.info('Successfully synced privacy center!');\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create privacy center! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import { ProcessingPurpose } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport {\n fetchAllProcessingPurposes,\n type ProcessingPurposeSubCategory,\n} from './fetchAllProcessingPurposes.js';\nimport {\n UPDATE_PROCESSING_PURPOSE_SUB_CATEGORIES,\n CREATE_PROCESSING_PURPOSE_SUB_CATEGORY,\n} from './gqls/processingPurpose.js';\n\nexport interface ProcessingPurposeInput {\n /** Name of processing purpose */\n name: string;\n /** Type of processing purpose */\n purpose: ProcessingPurpose;\n /** Description of processing purpose */\n description?: string;\n /** Owner email addresses */\n owners?: string[];\n /** Team names */\n teams?: string[];\n /** Attribute key-value pairs */\n attributes?: {\n /** Attribute key */\n key: string;\n /** Attribute values */\n values: string[];\n }[];\n}\n\n/**\n * Input to create a new processing purpose\n *\n * @param client - GraphQL client\n * @param processingPurpose - Input\n * @param options - Options\n * @returns Created processing purpose\n */\nexport async function createProcessingPurpose(\n client: GraphQLClient,\n options: {\n /** Processing purpose to create */\n input: ProcessingPurposeInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<ProcessingPurposeSubCategory, 'id' | 'name' | 'purpose'>> {\n const { input: processingPurpose, logger } = options;\n const gqlInput = {\n name: processingPurpose.name,\n purpose: processingPurpose.purpose,\n description: processingPurpose.description,\n // TODO: https://transcend.height.app/T-31994 - add attributes, teams, owners\n };\n\n const { createProcessingPurposeSubCategory } = await makeGraphQLRequest<{\n /** Create processing purpose mutation */\n createProcessingPurposeSubCategory: {\n /** Created processing purpose */\n processingPurposeSubCategory: ProcessingPurposeSubCategory;\n };\n }>(client, CREATE_PROCESSING_PURPOSE_SUB_CATEGORY, {\n variables: { input: gqlInput },\n logger,\n });\n return createProcessingPurposeSubCategory.processingPurposeSubCategory;\n}\n\n/**\n * Input to update processing purposes\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateProcessingPurposes(\n client: GraphQLClient,\n options: {\n /** [ProcessingPurposeInput, processingPurposeId] list */\n input: [ProcessingPurposeInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: processingPurposes, logger } = options;\n await makeGraphQLRequest(client, UPDATE_PROCESSING_PURPOSE_SUB_CATEGORIES, {\n variables: {\n input: {\n processingPurposeSubCategories: processingPurposes.map(([processingPurpose, id]) => ({\n id,\n description: processingPurpose.description,\n // TODO: https://transcend.height.app/T-31994 - add teams, owners\n attributes: processingPurpose.attributes,\n })),\n },\n },\n logger,\n });\n}\n\n/**\n * Sync the data inventory processing purposes\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncProcessingPurposes(\n client: GraphQLClient,\n inputs: ProcessingPurposeInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n\n logger.info(`Syncing \"${inputs.length}\" processing purposes...`);\n\n let encounteredError = false;\n\n const existingProcessingPurposes = await fetchAllProcessingPurposes(client, { logger });\n\n const processingPurposeByName: {\n [k in string]: Pick<ProcessingPurposeSubCategory, 'id' | 'name'>;\n } = keyBy(existingProcessingPurposes, ({ name, purpose }) => `${name}:${purpose}`);\n\n const newProcessingPurposes = inputs.filter(\n (input) => !processingPurposeByName[`${input.name}:${input.purpose}`],\n );\n\n await mapSeries(newProcessingPurposes, async (processingPurpose) => {\n try {\n const newProcessingPurpose = await createProcessingPurpose(client, {\n input: processingPurpose,\n logger,\n });\n processingPurposeByName[`${newProcessingPurpose.name}:${newProcessingPurpose.purpose}`] =\n newProcessingPurpose;\n logger.info(`Successfully synced processing purpose \"${processingPurpose.name}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to sync processing purpose \"${processingPurpose.name}\"! - ${(err as Error).message}`,\n );\n }\n });\n\n try {\n logger.info(`Updating \"${inputs.length}\" processing purposes!`);\n await updateProcessingPurposes(client, {\n input: inputs.map((input) => [\n input,\n processingPurposeByName[`${input.name}:${input.purpose}`]!.id,\n ]),\n logger,\n });\n logger.info(`Successfully synced \"${inputs.length}\" processing purposes!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to sync \"${inputs.length}\" processing purposes ! - ${(err as Error).message}`,\n );\n }\n\n return !encounteredError;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const REQUEST_ENRICHERS = gql`\n query TranscendCliRequestEnrichers($first: Int!, $offset: Int!, $requestId: ID!) {\n requestEnrichers(\n input: { requestId: $requestId }\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [\n { field: createdAt, direction: ASC }\n { field: title, direction: ASC, model: enricher }\n ]\n ) {\n nodes {\n id\n status\n enricher {\n id\n type\n title\n }\n }\n totalCount\n }\n }\n`;\n\nexport const RETRY_REQUEST_ENRICHER = gql`\n mutation TranscendCliRetryRequestEnricher($requestEnricherId: ID!) {\n retryRequestEnricher(id: $requestEnricherId) {\n requestEnricher {\n id\n }\n }\n }\n`;\n\nexport const SKIP_REQUEST_ENRICHER = gql`\n mutation TranscendCliSkipRequestEnricher($requestEnricherId: ID!) {\n skipRequestEnricher(id: $requestEnricherId) {\n requestEnricher {\n id\n }\n }\n }\n`;\n","import { RequestEnricherStatus } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { REQUEST_ENRICHERS } from './gqls/requestEnricher.js';\n\nexport interface RequestEnricher {\n /** ID of request enricher */\n id: string;\n /** Name of identifier */\n enricher: {\n /** ID of enricher */\n id: string;\n /** Title of enricher */\n title: string;\n /** Typeof of enricher */\n type: string;\n };\n /** The status of the enricher */\n status: RequestEnricherStatus;\n}\n\nconst PAGE_SIZE = 50;\n\n/**\n * Fetch all request enrichers for a particular request\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns List of request enrichers\n */\nexport async function fetchAllRequestEnrichers(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy: {\n /** ID of request to filter on */\n requestId: string;\n };\n },\n): Promise<RequestEnricher[]> {\n const {\n logger = NOOP_LOGGER,\n filterBy: { requestId },\n } = options;\n const requestEnrichers: RequestEnricher[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n requestEnrichers: { nodes },\n } = await makeGraphQLRequest<{\n /** Request Enrichers */\n requestEnrichers: {\n /** List */\n nodes: RequestEnricher[];\n };\n }>(client, REQUEST_ENRICHERS, {\n variables: { first: PAGE_SIZE, offset, requestId },\n logger,\n });\n requestEnrichers.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return requestEnrichers;\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const SOMBRA_VERSION: DocumentNode = parse(gql`\n query TranscendSombraVersion {\n organization {\n sombra {\n version\n }\n }\n }\n`);\n","import { IdentifierType } from '@transcend-io/privacy-types';\nimport { decodeCodec, valuesOf } from '@transcend-io/type-utils';\nimport type { Logger } from '@transcend-io/utils';\nimport type { Got } from 'got';\nimport { GraphQLClient } from 'graphql-request';\nimport * as t from 'io-ts';\nimport semver from 'semver';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { SOMBRA_VERSION } from './gqls/sombraVersion.js';\n\nconst MIN_SOMBRA_VERSION_TO_DECRYPT = '7.180.0';\n\nconst RequestIdentifier = t.type({\n /** ID of request */\n id: t.string,\n /** Name of identifier */\n name: t.string,\n /** The underlying identifier value */\n value: t.string,\n /** Type of identifier */\n type: valuesOf(IdentifierType),\n});\n\n/** Type override */\nexport type RequestIdentifier = t.TypeOf<typeof RequestIdentifier>;\n\nconst PAGE_SIZE = 50;\n\nexport const RequestIdentifiersResponse = t.type({\n identifiers: t.array(RequestIdentifier),\n});\n\n/**\n * Validate that the Sombra version meets the minimum requirement for\n * decrypting request identifiers. Call once before bulk-fetching identifiers\n * to avoid repeating this check on every request.\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function validateSombraVersion(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n const { logger = NOOP_LOGGER } = options;\n const {\n organization: {\n sombra: { version },\n },\n } = await makeGraphQLRequest<{\n /** The organization */\n organization: {\n /** Sombra */\n sombra: {\n /** Version string */\n version: string;\n };\n };\n }>(client, SOMBRA_VERSION, { logger });\n\n if (version && semver.lt(version, MIN_SOMBRA_VERSION_TO_DECRYPT)) {\n throw new Error(\n `Please upgrade Sombra to ${MIN_SOMBRA_VERSION_TO_DECRYPT} or greater to use this command.`,\n );\n }\n}\n\n/**\n * Fetch all request identifiers for a particular request\n *\n * @param client - GraphQL client\n * @param sombra - Sombra client\n * @param options - Options\n * @returns List of request identifiers\n */\nexport async function fetchAllRequestIdentifiers(\n client: GraphQLClient,\n sombra: Got,\n options: {\n /** Filter options */\n filterBy: {\n /** ID of request to filter on */\n requestId: string;\n };\n /** Skip the Sombra version check (caller already validated) */\n skipSombraCheck?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<RequestIdentifier[]> {\n const {\n filterBy: { requestId },\n skipSombraCheck = false,\n logger = NOOP_LOGGER,\n } = options;\n const requestIdentifiers: RequestIdentifier[] = [];\n let offset = 0;\n let shouldContinue = false;\n\n if (!skipSombraCheck) {\n await validateSombraVersion(client, { logger });\n }\n\n do {\n let response: unknown;\n try {\n response = await sombra!\n .post<{\n /** Decrypted identifiers */\n identifiers: RequestIdentifier[];\n }>('v1/request-identifiers', {\n json: {\n first: PAGE_SIZE,\n offset,\n requestId,\n },\n })\n .json();\n } catch (err) {\n throw new Error(`Failed to fetch request identifiers: ${(err as Error).message}`);\n }\n\n const { identifiers: nodes } = decodeCodec(RequestIdentifiersResponse, response);\n\n requestIdentifiers.push(...nodes);\n\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return requestIdentifiers;\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const REMOVE_REQUEST_IDENTIFIERS: DocumentNode = parse(gql`\n mutation TranscendCliRemoveRequestIdentifiers($input: RemoveRequestIdentifiersInput!) {\n removeRequestIdentifiers(input: $input) {\n count\n }\n }\n`);\n\nexport const REQUEST_IDENTIFIERS: DocumentNode = parse(gql`\n query TranscendCliRequestIdentifiers(\n $first: Int!\n $offset: Int!\n $requestIds: [ID!]\n $updatedAtBefore: Date\n $updatedAtAfter: Date\n ) {\n requestIdentifiers(\n input: {\n requestIds: $requestIds\n updatedAtBefore: $updatedAtBefore\n updatedAtAfter: $updatedAtAfter\n }\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n isVerifiedAtLeastOnce\n }\n totalCount\n }\n }\n`);\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { REQUEST_IDENTIFIERS } from './gqls/requestIdentifier.js';\n\nexport interface RequestIdentifierMetadata {\n /** ID of request identifier */\n id: string;\n /** Name of identifier */\n name: string;\n /** Status of identifier */\n isVerifiedAtLeastOnce: boolean;\n}\n\nconst PAGE_SIZE = 50;\n\n/**\n * Fetch all request identifier metadata for a particular request\n *\n * @param client - GraphQL client\n * @param options - Filter options\n * @returns List of request identifiers\n */\nexport async function fetchAllRequestIdentifierMetadata(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** ID of request to filter on */\n requestId?: string;\n /** IDs of requests to filter on */\n requestIds?: string[];\n /** Filter for request identifiers updated before this date */\n updatedAtBefore?: Date;\n /** Filter for request identifiers updated after this date */\n updatedAtAfter?: Date;\n };\n } = {},\n): Promise<RequestIdentifierMetadata[]> {\n const { logger = NOOP_LOGGER, filterBy } = options;\n const { requestId, requestIds, updatedAtBefore, updatedAtAfter } = filterBy ?? {};\n const resolvedRequestIds = requestIds ?? (requestId ? [requestId] : undefined);\n const requestIdentifiers: RequestIdentifierMetadata[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n requestIdentifiers: { nodes },\n } = await makeGraphQLRequest<{\n /** Request Identifiers */\n requestIdentifiers: {\n /** List */\n nodes: RequestIdentifierMetadata[];\n };\n }>(client, REQUEST_IDENTIFIERS, {\n variables: {\n first: PAGE_SIZE,\n offset,\n requestIds: resolvedRequestIds,\n updatedAtBefore: updatedAtBefore ? updatedAtBefore.toISOString() : undefined,\n updatedAtAfter: updatedAtAfter ? updatedAtAfter.toISOString() : undefined,\n },\n logger,\n });\n requestIdentifiers.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return requestIdentifiers;\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const DATA_SUBJECTS: DocumentNode = parse(gql`\n query TranscendCliDataSubjects {\n internalSubjects {\n id\n title {\n defaultMessage\n }\n active\n type\n adminDashboardDefaultSilentMode\n actions {\n type\n }\n }\n }\n`);\n\nexport const CREATE_DATA_SUBJECT: DocumentNode = parse(gql`\n mutation TranscendCliCreateDataSubject($type: String!) {\n createSubject(input: { type: $type, title: $type, subjectClass: OTHER }) {\n subject {\n id\n type\n }\n }\n }\n`);\n\nexport const UPDATE_DATA_SUBJECT: DocumentNode = parse(gql`\n mutation TranscendCliUpdateDataSubject($input: UpdateSubjectInput!) {\n updateSubject(input: $input) {\n clientMutationId\n }\n }\n`);\n\nexport const TOGGLE_DATA_SUBJECT: DocumentNode = parse(gql`\n mutation TranscendCliToggleDataSubject($input: ToggleSubjectInput!) {\n toggleSubject(input: $input) {\n clientMutationId\n }\n }\n`);\n","import { RequestActionObjectResolver } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { CREATE_DATA_SUBJECT, DATA_SUBJECTS } from './gqls/dataSubject.js';\n\nexport interface DataSubject {\n /** ID of data subject */\n id: string;\n /** Type of data subject */\n type: string;\n /** Whether active */\n active: boolean;\n /** Title of data subject */\n title: {\n /** Default message */\n defaultMessage: string;\n };\n /** Whether silent mode is enabled by default */\n adminDashboardDefaultSilentMode: boolean;\n /** Enabled actions */\n actions: {\n /** Type of action */\n type: RequestActionObjectResolver;\n }[];\n}\n\n/**\n * Fetch all data subjects in an organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns List of data subject configurations\n */\nexport async function fetchAllDataSubjects(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<DataSubject[]> {\n const { logger = NOOP_LOGGER } = options;\n const { internalSubjects } = await makeGraphQLRequest<{\n /** Query response */\n internalSubjects: DataSubject[];\n }>(client, DATA_SUBJECTS, { logger });\n return internalSubjects;\n}\n\n/**\n * Create a single data subject\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Created data subject\n */\nexport async function createDataSubject(\n client: GraphQLClient,\n options: {\n /** The type string for the new subject */\n input: string;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<DataSubject> {\n const { input: dataSubjectType, logger = NOOP_LOGGER } = options;\n const { createSubject } = await makeGraphQLRequest<{\n /** Create Subject Response */\n createSubject: {\n /** Created Data Subject */\n subject: DataSubject;\n };\n }>(client, CREATE_DATA_SUBJECT, {\n variables: { type: dataSubjectType, skipPublish: true },\n logger,\n });\n return createSubject.subject;\n}\n\n/**\n * Convert a list of data subject types into the block list of IDs to assign to the data silo\n *\n * @param dataSubjectTypes - The list of data subject types that the data silo should be for\n * @param allDataSubjects - All data subjects in the organization\n * @returns The block list of data subject ids to not process against this data silo\n */\nexport function convertToDataSubjectBlockList(\n dataSubjectTypes: string[],\n allDataSubjects: { [type in string]: DataSubject },\n): string[] {\n dataSubjectTypes.forEach((type) => {\n if (!allDataSubjects[type]) {\n throw new Error(`Expected to find data subject definition: ${type}`);\n }\n });\n\n return Object.values(allDataSubjects)\n .filter((silo) => !dataSubjectTypes.includes(silo.type))\n .map(({ id }) => id);\n}\n\n/**\n * Convert a list of data subject types into the allow list of types\n *\n * @param dataSubjectTypes - The list of data subject types that the data silo should be for\n * @param allDataSubjects - All data subjects in the organization\n * @returns The allow list of data subjects for that silo\n */\nexport function convertToDataSubjectAllowlist(\n dataSubjectTypes: string[],\n allDataSubjects: { [type in string]: DataSubject },\n): string[] {\n dataSubjectTypes.forEach((type) => {\n if (!allDataSubjects[type]) {\n throw new Error(`Expected to find data subject definition: ${type}`);\n }\n });\n\n return Object.values(allDataSubjects)\n .filter((silo) => !dataSubjectTypes.includes(silo.type))\n .map(({ type }) => type);\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const NEW_IDENTIFIER_TYPES: DocumentNode = parse(gql`\n query TranscendCliNewIdentifierTypes {\n newIdentifierTypes {\n name\n }\n }\n`);\n\nexport const CREATE_IDENTIFIER: DocumentNode = parse(gql`\n mutation TranscendCliCreateIdentifier($input: IdentifierInput!) {\n createIdentifier(input: $input) {\n identifier {\n id\n name\n }\n }\n }\n`);\n\nexport const UPDATE_IDENTIFIER: DocumentNode = parse(gql`\n mutation TranscendCliUpdateIdentifier($input: UpdateIdentifierInput!) {\n updateIdentifier(input: $input) {\n clientMutationId\n }\n }\n`);\n","import { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy, uniq, flatten, difference } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllIdentifiers, type Identifier } from '../data-inventory/fetchAllIdentifiers.js';\nimport { CREATE_IDENTIFIER, NEW_IDENTIFIER_TYPES } from './gqls/dsrIdentifier.js';\n\nexport interface IdentifiersAndCreateMissingInput {\n /** Enricher configurations */\n enrichers?: {\n /** Input identifier name */\n 'input-identifier'?: string;\n /** Output identifier names */\n 'output-identifiers': string[];\n }[];\n /** Data silo configurations */\n 'data-silos'?: {\n /** Identity keys */\n 'identity-keys'?: string[];\n }[];\n /** Identifier configurations */\n identifiers?: {\n /** Identifier name */\n name: string;\n }[];\n}\n\n/**\n * Fetch all identifiers and if any are found in the config that are\n * missing, create those identifiers.\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns A map from identifier name to Identifier\n */\nexport async function fetchIdentifiersAndCreateMissing(\n client: GraphQLClient,\n options: {\n /** Transcend input configuration */\n input: IdentifiersAndCreateMissingInput;\n /** When true, skip publishing to privacy center */\n skipPublish?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<{ [k in string]: Identifier }> {\n const { input, skipPublish = false, logger = NOOP_LOGGER } = options;\n const { enrichers = [], 'data-silos': dataSilos = [], identifiers = [] } = input;\n const allIdentifiers = await fetchAllIdentifiers(client, { logger });\n const identifiersByName = keyBy(allIdentifiers, 'name');\n\n const expectedIdentifiers = uniq([\n ...flatten(\n enrichers.map((enricher) => [\n enricher['input-identifier'],\n ...enricher['output-identifiers'],\n ]),\n ),\n ...flatten(dataSilos.map((dataSilo) => dataSilo['identity-keys'])),\n ...identifiers.map(({ name }) => name),\n ]).filter((x) => !!x);\n const missingIdentifiers = difference(\n expectedIdentifiers,\n allIdentifiers.map(({ name }) => name),\n );\n\n if (missingIdentifiers.length > 0) {\n logger.info(`Creating ${missingIdentifiers.length} new identifiers...`);\n const { newIdentifierTypes } = await makeGraphQLRequest<{\n /** Query response */\n newIdentifierTypes: {\n /** Name of identifier type remaining */\n name: string;\n }[];\n }>(client, NEW_IDENTIFIER_TYPES, { logger });\n const nativeTypesRemaining = newIdentifierTypes.map(({ name }) => name);\n await mapSeries(missingIdentifiers, async (identifier) => {\n logger.info(`Creating identifier ${identifier}...`);\n try {\n const { createIdentifier } = await makeGraphQLRequest<{\n /** createIdentifier Response */\n createIdentifier: {\n /** Created identifier */\n identifier: Identifier;\n };\n }>(client, CREATE_IDENTIFIER, {\n variables: {\n input: {\n name: identifier,\n type: nativeTypesRemaining.includes(identifier!) ? identifier : 'custom',\n skipPublish,\n },\n },\n logger,\n });\n logger.info(`Created identifier ${identifier}!`);\n\n identifiersByName[identifier!] = createIdentifier.identifier;\n } catch (err) {\n logger.error(`Failed to create identifier \"${identifier}\" - ${(err as Error).message}`);\n }\n });\n }\n return identifiersByName;\n}\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { RETRY_REQUEST_ENRICHER } from './gqls/requestEnricher.js';\n\n/**\n * Retry a request enricher\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function retryRequestEnricher(\n client: GraphQLClient,\n options: {\n /** The ID of the request enricher to restart */\n id: string;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { id, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, RETRY_REQUEST_ENRICHER, {\n variables: { requestEnricherId: id },\n logger,\n });\n}\n","import { RequestAction } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { TOGGLE_DATA_SUBJECT, UPDATE_DATA_SUBJECT } from './gqls/dataSubject.js';\n\nexport interface DataSubjectInput {\n /** The type of the data subject */\n type: string;\n /** Whether the data subject is active on the Privacy Center & DSR API */\n active?: boolean;\n /** The title of the data subject */\n title?: string;\n /** Whether or not to default new requests made in the admin dashboard to silent mode */\n adminDashboardDefaultSilentMode?: boolean;\n /** Enabled request actions for the data subject */\n actions?: RequestAction[];\n}\n\n/**\n * Sync the data subjects\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function syncDataSubject(\n client: GraphQLClient,\n options: {\n /** DataSubject update input */\n input: DataSubjectInput;\n /** Existing data subject Id */\n dataSubjectId: string;\n /** When true, skip publishing to privacy center */\n skipPublish?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: dataSubject, dataSubjectId, skipPublish = false, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_DATA_SUBJECT, {\n variables: {\n input: {\n id: dataSubjectId,\n title: dataSubject.title,\n adminDashboardDefaultSilentMode: dataSubject.adminDashboardDefaultSilentMode,\n actions: dataSubject.actions,\n skipPublish: skipPublish && typeof dataSubject.active === 'undefined',\n },\n },\n logger,\n });\n\n if (typeof dataSubject.active === 'boolean') {\n await makeGraphQLRequest(client, TOGGLE_DATA_SUBJECT, {\n variables: {\n input: {\n id: dataSubjectId,\n active: dataSubject.active,\n skipPublish,\n },\n },\n logger,\n });\n }\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const ENRICHERS = gql`\n query TranscendCliEnrichers($title: String, $first: Int!, $offset: Int!) {\n enrichers(\n filterBy: { text: $title }\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [{ field: createdAt, direction: ASC }, { field: title, direction: ASC }]\n ) {\n nodes {\n id\n title\n url\n type\n expirationDuration\n lookerQueryTitle\n testRegex\n transitionRequestStatus\n phoneNumbers\n regionList\n inputIdentifier {\n name\n }\n identifiers {\n name\n }\n dataSubjects {\n type\n }\n actions\n }\n }\n }\n`;\n\nexport interface Initializer {\n /** ID of enricher */\n id: string;\n /** Identifiers */\n identifiers: {\n /** Name of identifier */\n name: string;\n }[];\n}\n\nexport const INITIALIZER = gql`\n query TranscendCliInitializer {\n initializer {\n id\n identifiers {\n name\n }\n }\n }\n`;\n\nexport const CREATE_ENRICHER = gql`\n mutation TranscendCliCreateEnricher($input: EnricherInput!) {\n createEnricher(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const UPDATE_ENRICHER = gql`\n mutation TranscendCliUpdateEnricher($input: UpdateEnricherInput!) {\n updateEnricher(input: $input) {\n clientMutationId\n }\n }\n`;\n","import {\n EnricherType,\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n PreflightRequestStatus,\n RequestAction,\n} from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport type { Identifier } from '../data-inventory/fetchAllIdentifiers.js';\nimport { ENRICHERS, CREATE_ENRICHER, UPDATE_ENRICHER } from './gqls/enricher.js';\n\nexport interface EnricherInput {\n /** The display title of the enricher */\n title: string;\n /** The names of the identifiers that can be resolved by this enricher */\n 'output-identifiers': string[];\n /** Internal description for why the enricher is needed */\n description?: string;\n /** The URL of the enricher */\n url?: string;\n /** The type of enricher */\n type?: EnricherType;\n /** The name of the identifier that will be the input to this enricher */\n 'input-identifier'?: string;\n /** A regular expression that can be used to match on for cancellation */\n testRegex?: string;\n /** For looker integration - the title of the looker query to run */\n lookerQueryTitle?: string;\n /** The duration (in ms) that the enricher should take to execute */\n expirationDuration?: number;\n /** The status that the enricher should transfer to when condition is met */\n transitionRequestStatus?: PreflightRequestStatus;\n /** For twilio integration - the phone numbers that can be used to send text codes */\n phoneNumbers?: string[];\n /** The list of regions that should trigger the preflight check */\n regionList?: (IsoCountryCode | IsoCountrySubdivisionCode)[];\n /** Specify which data subjects the enricher should run for */\n 'data-subjects'?: string[];\n /** Headers to include in the webhook */\n headers?: {\n /** Header name */\n name: string;\n /** Header value */\n value: string;\n /** Whether the value is a secret */\n isSecret?: boolean;\n }[];\n /** The privacy actions that the enricher should run against */\n 'privacy-actions'?: RequestAction[];\n}\n\nexport interface Enricher {\n /** ID of enricher */\n id: string;\n /** Title of enricher */\n title: string;\n /** URL of enricher */\n url: string;\n /** Server silo */\n type: EnricherType;\n /** Input identifier */\n inputIdentifier: {\n /** Identifier name */\n name: string;\n };\n /** The selected actions */\n actions: RequestAction[];\n /** Output identifiers */\n identifiers: {\n /** Identifier name */\n name: string;\n }[];\n /** Data subjects that the preflight check is configured for */\n dataSubjects: {\n /** Data subject type */\n type: string;\n }[];\n /** The duration (in ms) that the enricher should take to execute. - BigInt */\n expirationDuration: string;\n /** Looker query title */\n lookerQueryTitle?: string;\n /** A regular expression that can be used to match on for cancelation */\n testRegex?: string;\n /** The status that the enricher should transfer to when condition is met. */\n transitionRequestStatus?: PreflightRequestStatus;\n /** The twilio phone number to send from */\n phoneNumbers: string[];\n /** The list of regions that should trigger the enrichment condition */\n regionList: (IsoCountryCode | IsoCountrySubdivisionCode)[];\n}\n\nexport interface DataSubjectRef {\n /** ID of data subject */\n id: string;\n /** Type of data subject */\n type: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all enrichers in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All enrichers in the organization\n */\nexport async function fetchAllEnrichers(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** Filter by title */\n title?: string;\n };\n } = {},\n): Promise<Enricher[]> {\n const { logger = NOOP_LOGGER, filterBy } = options;\n const { title } = filterBy ?? {};\n const enrichers: Enricher[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n enrichers: { nodes },\n } = await makeGraphQLRequest<{\n /** Query response */\n enrichers: {\n /** List of matches */\n nodes: Enricher[];\n };\n }>(client, ENRICHERS, {\n variables: { first: PAGE_SIZE, offset, title },\n logger,\n });\n enrichers.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return enrichers.sort((a, b) => a.title.localeCompare(b.title));\n}\n\n/**\n * Sync an enricher configuration\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function syncEnricher(\n client: GraphQLClient,\n options: {\n /** The enricher input */\n input: EnricherInput;\n /** Index of identifiers in the organization */\n identifierByName: { [name in string]: Identifier };\n /** Lookup data subject by name */\n dataSubjectsByName: { [name in string]: DataSubjectRef };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: enricher, identifierByName, dataSubjectsByName, logger = NOOP_LOGGER } = options;\n const matches = await fetchAllEnrichers(client, {\n filterBy: { title: enricher.title },\n logger,\n });\n const existingEnricher = matches.find(({ title }) => title === enricher.title);\n\n const dataSubjectIds = enricher['data-subjects']?.map((subject) => {\n const existing = dataSubjectsByName[subject];\n if (!existing) {\n throw new Error(`Failed to find a data subject with name: ${subject}`);\n }\n return existing.id;\n });\n\n const inputIdentifier = enricher['input-identifier'];\n const actionUpdates = enricher['privacy-actions'] || Object.values(RequestAction);\n if (existingEnricher) {\n await makeGraphQLRequest(client, UPDATE_ENRICHER, {\n variables: {\n input: {\n id: existingEnricher.id,\n title: enricher.title,\n url: enricher.url,\n headers: enricher.headers,\n testRegex: enricher.testRegex,\n lookerQueryTitle: enricher.lookerQueryTitle,\n expirationDuration:\n typeof enricher.expirationDuration === 'number'\n ? enricher.expirationDuration.toString()\n : undefined,\n transitionRequestStatus: enricher.transitionRequestStatus,\n phoneNumbers: enricher.phoneNumbers,\n regionList: enricher.regionList,\n dataSubjectIds,\n description: enricher.description || '',\n inputIdentifier: inputIdentifier ? identifierByName[inputIdentifier]!.id : undefined,\n identifiers: enricher['output-identifiers']!.map((id) => identifierByName[id]!.id),\n ...(existingEnricher.type === EnricherType.Sombra ? {} : { actions: actionUpdates }),\n },\n },\n logger,\n });\n } else if (inputIdentifier) {\n await makeGraphQLRequest(client, CREATE_ENRICHER, {\n variables: {\n input: {\n title: enricher.title,\n url: enricher.url,\n type: enricher.type || EnricherType.Server,\n headers: enricher.headers,\n testRegex: enricher.testRegex,\n lookerQueryTitle: enricher.lookerQueryTitle,\n expirationDuration:\n typeof enricher.expirationDuration === 'number'\n ? enricher.expirationDuration.toString()\n : undefined,\n transitionRequestStatus: enricher.transitionRequestStatus,\n phoneNumbers: enricher.phoneNumbers,\n dataSubjectIds,\n regionList: enricher.regionList,\n description: enricher.description || '',\n inputIdentifier: identifierByName[inputIdentifier]!.id,\n identifiers: enricher['output-identifiers'].map((id) => identifierByName[id]!.id),\n actions: actionUpdates,\n },\n },\n logger,\n });\n }\n}\n","import { RequestAction } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport type { DataSubject } from './fetchDataSubjects.js';\nimport { UPDATE_IDENTIFIER } from './gqls/dsrIdentifier.js';\n\nexport interface IdentifierInput {\n /** The name of the identifier */\n name: string;\n /** The type of the identifier */\n type: string;\n /** Regular expression to verify the identifier */\n regex?: string;\n /** The fixed set of options that an identifier can take on */\n selectOptions?: string[];\n /** Whether or not the identifier is shown in the privacy center form */\n privacyCenterVisibility?: RequestAction[];\n /** The set of data subjects that this identifier is enabled for */\n dataSubjects?: string[];\n /** When true, the identifier is a required field on the privacy center form */\n isRequiredInForm?: boolean;\n /** Placeholder message for identifier */\n placeholder?: string;\n /** Display title for identifier */\n displayTitle?: string;\n /** Display description for identifier */\n displayDescription?: string;\n /** The display order for the identifier */\n displayOrder?: number;\n /** Whether or not the identifier is unique on the preference store */\n isUniqueOnPreferenceStore?: boolean;\n}\n\n/**\n * Sync a single identifier\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function syncIdentifier(\n client: GraphQLClient,\n options: {\n /** Identifier update input */\n input: IdentifierInput;\n /** Data subject lookup by name */\n dataSubjectsByName: { [k in string]: DataSubject };\n /** Existing identifier Id */\n identifierId: string;\n /** When true, skip publishing to privacy center */\n skipPublish?: boolean;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const {\n input: identifier,\n dataSubjectsByName,\n identifierId,\n skipPublish = false,\n logger = NOOP_LOGGER,\n } = options;\n await makeGraphQLRequest(client, UPDATE_IDENTIFIER, {\n variables: {\n input: {\n id: identifierId,\n selectOptions: identifier.selectOptions,\n isRequiredInForm: identifier.isRequiredInForm,\n regex: identifier.regex,\n placeholder: identifier.placeholder,\n displayTitle: identifier.displayTitle,\n displayDescription: identifier.displayDescription,\n displayOrder: identifier.displayOrder,\n isUniqueOnPreferenceStore: identifier.isUniqueOnPreferenceStore,\n privacyCenterVisibility: identifier.privacyCenterVisibility,\n dataSubjectIds: identifier.dataSubjects\n ? identifier.dataSubjects.map((type) => dataSubjectsByName[type]!.id)\n : undefined,\n skipPublish,\n },\n },\n logger,\n });\n}\n","import { gql } from 'graphql-request';\n\nexport const ADD_SILO_DISCOVERY_RESULTS = gql`\n mutation AddSiloDiscoveryResults($pluginId: ID!, $rawResults: [SiloDiscoveryRawResultInput!]!) {\n addSiloDiscoveryResults(input: { pluginId: $pluginId, rawResults: $rawResults }) {\n success\n }\n }\n`;\n\nexport const ENABLED_PLUGINS = gql`\n query Plugins($dataSiloId: String!, $type: PluginType!) {\n plugins(filterBy: { dataSiloId: $dataSiloId, type: $type, enabled: true }) {\n plugins {\n id\n dataSilo {\n type\n }\n }\n totalCount\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { ENABLED_PLUGINS } from './gqls/siloDiscovery.js';\n\nexport interface Plugin {\n /** Associated data silo */\n dataSilo: {\n /** The type of plugin */\n type: string;\n };\n /** The ID of this plugin */\n id: string;\n}\n\nexport interface PluginResponse {\n /** The key object of the response */\n plugins: {\n /** The total count */\n totalCount: number;\n /** The list of plugins */\n plugins: Plugin[];\n };\n}\n\n/**\n * Fetch a data silo discovery plugin\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns An active data silo plugin (if multiple, returns the first)\n */\nexport async function fetchActiveSiloDiscoPlugin(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy: {\n /** The data silo to look up plugins for */\n dataSiloId: string;\n };\n },\n): Promise<Plugin> {\n const {\n logger = NOOP_LOGGER,\n filterBy: { dataSiloId },\n } = options;\n const response = await makeGraphQLRequest<PluginResponse>(client, ENABLED_PLUGINS, {\n variables: {\n dataSiloId,\n type: 'DATA_SILO_DISCOVERY',\n },\n logger,\n });\n\n const { plugins, totalCount } = response.plugins;\n if (totalCount === 0) {\n logger.error('No active data silo plugins found for this data silo.');\n process.exit(1);\n }\n\n return plugins[0]!;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\nexport const ACTIONS = gql`\n query TranscendCliActions($first: Int!, $offset: Int!) {\n actions(\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [{ field: type, direction: ASC }]\n ) {\n nodes {\n id\n type\n skipSecondaryIfNoFiles\n skipDownloadableStep\n requiresReview\n regionList\n regionDetectionMethod\n waitingPeriod\n }\n }\n }\n`;\n\nexport const UPDATE_ACTION = gql`\n mutation TranscendCliUpdateAction($input: UpdateActionInput!) {\n updateAction(input: $input) {\n clientMutationId\n }\n }\n`;\n","import {\n IsoCountryCode,\n IsoCountrySubdivisionCode,\n RegionDetectionMethod,\n RequestAction,\n} from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { ACTIONS } from './gqls/action.js';\n\nexport interface Action {\n /** ID of identifier */\n id: string;\n /** Type of action */\n type: RequestAction;\n /** Whether to skip secondary when no files exist */\n skipSecondaryIfNoFiles: boolean;\n /** Whether to skip downloadable step */\n skipDownloadableStep: boolean;\n /** Whether action requires review */\n requiresReview: boolean;\n /** Waiting period for action */\n waitingPeriod: number;\n /** Method in which the data subject's region is detected */\n regionDetectionMethod: RegionDetectionMethod;\n /** The list of regions to show in the form */\n regionList: (IsoCountryCode | IsoCountrySubdivisionCode)[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all actions in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All actions in the organization\n */\nexport async function fetchAllActions(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Action[]> {\n const { logger } = options;\n const actions: Action[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n actions: { nodes },\n } = await makeGraphQLRequest<{\n /** Actions */\n actions: {\n /** List */\n nodes: Action[];\n };\n }>(client, ACTIONS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n actions.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return actions.sort((a, b) => a.type.localeCompare(b.type));\n}\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { ATTRIBUTE_KEYS_REQUESTS } from '../administration/gqls/attributeKey.js';\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\n\nexport interface AttributeKey {\n /** ID of attribute key */\n id: string;\n /** Name of attribute key */\n name: string;\n /** Attribute key type */\n type: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all attribute keys enabled for privacy requests\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All attribute keys in the organization\n */\nexport async function fetchAllRequestAttributeKeys(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<AttributeKey[]> {\n const { logger } = options;\n const attributeKeys: AttributeKey[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n attributeKeys: { nodes },\n } = await makeGraphQLRequest<{\n /** Query response */\n attributeKeys: {\n /** List of matches */\n nodes: AttributeKey[];\n };\n }>(client, ATTRIBUTE_KEYS_REQUESTS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n attributeKeys.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return attributeKeys.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\nexport const SILO_DISCOVERY_RESULTS = gql`\n query TranscendCliSiloDiscoveryResults($first: Int!, $offset: Int!) {\n siloDiscoveryResults(first: $first, offset: $offset) {\n nodes {\n title\n resourceId\n country\n countrySubDivision\n plaintextContext\n status\n containsSensitiveData\n suggestedCatalog {\n title\n }\n plugin {\n dataSilo {\n title\n }\n }\n }\n }\n }\n`;\n","import type { IsoCountryCode, IsoCountrySubdivisionCode } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { SILO_DISCOVERY_RESULTS } from './gqls/siloDiscoveryResult.js';\n\nexport interface SiloDiscoveryResult {\n /** Title of silo discovery result */\n title?: string;\n /** Resource ID of silo discovery result */\n resourceId: string;\n /** Suggested catalog */\n suggestedCatalog: {\n /** Title for the suggested catalog */\n title: string;\n };\n /** The likelihood that data is sensitive for this results */\n containsSensitiveData: string;\n /** The status of silo discovery triage */\n status: string;\n /** Hosting country of data silo discovery result */\n country?: IsoCountryCode;\n /** Hosting subdivision data silo discovery result */\n countrySubDivision?: IsoCountrySubdivisionCode;\n /** Plaintext context data silo discovery result */\n plaintextContext: string;\n /** The plugin that found this result */\n plugin: {\n /** The data silo the plugin belongs to */\n dataSilo: {\n /** The internal display title */\n title: string;\n };\n };\n}\n\nconst PAGE_SIZE = 30;\n\n/**\n * Fetch all silo discovery results in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All silo discovery results in the organization\n */\nexport async function fetchAllSiloDiscoveryResults(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<SiloDiscoveryResult[]> {\n const { logger } = options;\n const siloDiscoveryResults: SiloDiscoveryResult[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n siloDiscoveryResults: { nodes },\n } = await makeGraphQLRequest<{\n /** Discovery results */\n siloDiscoveryResults: {\n /** Nodes */\n nodes: SiloDiscoveryResult[];\n };\n }>(client, SILO_DISCOVERY_RESULTS, {\n variables: { first: PAGE_SIZE, offset, input: {}, filterBy: {} },\n logger,\n });\n\n const titledNodes = nodes.map((node) =>\n node.title === null && node.suggestedCatalog?.title\n ? { ...node, title: node.suggestedCatalog.title }\n : node,\n );\n\n siloDiscoveryResults.push(...titledNodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return siloDiscoveryResults;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const CATALOGS = gql`\n query TranscendCliCatalogs($first: Int!, $offset: Int!) {\n catalogs(first: $first, offset: $offset, filterBy: {}, useMaster: false) {\n nodes {\n integrationName\n title\n hasApiFunctionality\n }\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { CATALOGS } from './gqls/catalog.js';\n\nexport interface Catalog {\n /** Integration name */\n integrationName: string;\n /** Title of Data Silo */\n title: string;\n /** Whether API is supported */\n hasApiFunctionality: boolean;\n}\n\nconst PAGE_SIZE = 100;\n\n/**\n * Fetch all integration catalogs in an organization\n *\n * @param client - Client\n * @param options - Options\n * @returns Integration catalogs\n */\nexport async function fetchAllCatalogs(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Catalog[]> {\n const { logger } = options;\n const catalogs: Catalog[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n catalogs: { nodes },\n } = await makeGraphQLRequest<{\n /** integration catalogs */\n catalogs: {\n /** List */\n nodes: Catalog[];\n };\n }>(client, CATALOGS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n catalogs.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n return catalogs.sort((a, b) => a.integrationName.localeCompare(b.integrationName));\n}\n\nexport interface IndexedCatalogs {\n /** Mapping from service name to service title */\n serviceToTitle: { [k in string]: string };\n /** Mapping from service name to boolean indicate if service has API integration support */\n serviceToSupportedIntegration: { [k in string]: boolean };\n}\n\n/**\n * Fetch all integration catalogs and index them for usage in common utility manners\n *\n * @param client - Client\n * @param options - Options\n * @returns Integration catalogs\n */\nexport async function fetchAndIndexCatalogs(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<\n {\n /** List of all catalogs */\n catalogs: Catalog[];\n } & IndexedCatalogs\n> {\n const catalogs = await fetchAllCatalogs(client, options);\n\n const serviceToTitle = catalogs.reduce(\n (acc, catalog) => Object.assign(acc, { [catalog.integrationName]: catalog.title }),\n {} as { [k in string]: string },\n );\n\n const serviceToSupportedIntegration = catalogs.reduce(\n (acc, catalog) =>\n Object.assign(acc, {\n [catalog.integrationName]: catalog.hasApiFunctionality,\n }),\n {} as { [k in string]: boolean },\n );\n\n return {\n catalogs,\n serviceToTitle,\n serviceToSupportedIntegration,\n };\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const REQUEST_DATA_SILOS = gql`\n query TranscendCliRequestDataSilos(\n $first: Int!\n $offset: Int!\n $filterBy: RequestDataSiloFiltersInput!\n ) {\n requestDataSilos(\n filterBy: $filterBy\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [\n { field: createdAt, direction: DESC }\n { field: title, direction: ASC, model: dataSilo }\n ]\n ) {\n nodes {\n id\n request {\n type\n }\n }\n totalCount\n }\n }\n`;\n\nexport const CHANGE_REQUEST_DATA_SILO_STATUS = gql`\n mutation TranscendCliMarkRequestDataSiloCompleted(\n $requestDataSiloId: ID!\n $status: UpdateRequestDataSiloStatus!\n ) {\n changeRequestDataSiloStatus(input: { id: $requestDataSiloId, status: $status }) {\n requestDataSilo {\n id\n }\n }\n }\n`;\n\nexport const RETRY_REQUEST_DATA_SILO = gql`\n mutation TranscendCliRetryRequestDataSilo($requestDataSiloId: ID!) {\n retryRequestDataSilo(id: $requestDataSiloId) {\n requestDataSilo {\n id\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\n// orderBy: [\n// { field: createdAt, direction: DESC }\n// { field: title, direction: ASC, model: dataSilo }\n// ]\nexport const REDUCED_REQUESTS_FOR_DATA_SILO_COUNT = gql`\n query TranscendCliListReducedRequestsForDataSiloCount(\n $input: BulkCompletionReducedRequestInput!\n ) {\n listReducedRequestsForDataSilo(input: $input) {\n totalCount\n }\n }\n`;\n","import { RequestAction, RequestDataSiloStatus, RequestStatus } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { REQUEST_DATA_SILOS } from './gqls/requestDataSilo.js';\n\nexport interface RequestDataSilo {\n /** ID of RequestDataSilo */\n id: string;\n /** Request */\n request: {\n /** Type of request */\n type: RequestAction;\n };\n}\n\nexport interface RequestDataSiloFilters {\n /** ID of request to filter on */\n requestId?: string;\n /** Data silo ID */\n dataSiloId?: string;\n /** The statuses to filter on */\n statuses?: RequestDataSiloStatus[];\n /** The request statuses to filter on */\n requestStatuses?: RequestStatus[];\n}\n\n/**\n * Fetch a count of request data silos\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Count of request data silos\n */\nexport async function fetchRequestDataSilosCount(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: RequestDataSiloFilters;\n } = {},\n): Promise<number> {\n const { logger, filterBy: { requestId, dataSiloId, requestStatuses, statuses } = {} } = options;\n const {\n requestDataSilos: { totalCount },\n } = await makeGraphQLRequest<{\n /** Request Data Silos */\n requestDataSilos: {\n /** List */\n nodes: RequestDataSilo[];\n /** Total count */\n totalCount: number;\n };\n }>(client, REQUEST_DATA_SILOS, {\n variables: {\n first: 1,\n offset: 0,\n filterBy: {\n dataSiloId,\n requestId,\n status: statuses,\n requestStatus: requestStatuses,\n },\n },\n logger,\n });\n\n return totalCount;\n}\n\nconst PAGE_SIZE = 100;\n\n/**\n * Fetch all request data silos by some filter criteria\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns List of request data silos\n */\nexport async function fetchRequestDataSilos(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: RequestDataSiloFilters;\n /** Limit on number of requests */\n limit?: number;\n /** Handle progress updates */\n onProgress?: (numUpdated: number) => void;\n } = {},\n): Promise<RequestDataSilo[]> {\n const {\n logger,\n filterBy: { requestId, dataSiloId, requestStatuses, statuses } = {},\n limit,\n onProgress,\n } = options;\n const requestDataSilos: RequestDataSilo[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n requestDataSilos: { nodes },\n } = await makeGraphQLRequest<{\n /** Request Data Silos */\n requestDataSilos: {\n /** List */\n nodes: RequestDataSilo[];\n /** Total count */\n totalCount: number;\n };\n }>(client, REQUEST_DATA_SILOS, {\n variables: {\n first: PAGE_SIZE,\n offset,\n filterBy: {\n dataSiloId,\n requestId,\n status: statuses,\n requestStatus: requestStatuses,\n },\n },\n logger,\n });\n requestDataSilos.push(...nodes);\n\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n onProgress?.(nodes.length);\n } while (shouldContinue && (!limit || offset < limit));\n\n return requestDataSilos;\n}\n\n/**\n * Fetch a single request data silo by request and data silo IDs\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns The matching request data silo\n */\nexport async function fetchRequestDataSilo(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy: {\n /** ID of request to filter on */\n requestId: string;\n /** Data silo ID */\n dataSiloId: string;\n };\n },\n): Promise<RequestDataSilo> {\n const {\n logger,\n filterBy: { requestId, dataSiloId },\n } = options;\n const nodes = await fetchRequestDataSilos(client, {\n logger,\n filterBy: { requestId, dataSiloId },\n });\n if (nodes.length !== 1) {\n throw new Error(\n `Failed to find RequestDataSilo with requestId:${requestId},dataSiloId:${dataSiloId}`,\n );\n }\n\n return nodes[0]!;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const REQUEST_FILES = gql`\n query TranscendCliRequestFiles($first: Int!, $offset: Int!, $filterBy: RequestFileFiltersInput!) {\n requestFiles(\n filterBy: $filterBy\n first: $first\n offset: $offset\n orderBy: [{ field: createdAt, direction: ASC }, { field: id, direction: ASC }]\n ) {\n nodes {\n remoteId\n fileName\n }\n }\n }\n`;\n\nexport const BULK_REQUEST_FILES = gql`\n query TranscendCliBulkRequestFiles(\n $filterBy: BulkRequestFilesFiltersInput!\n $first: Int!\n $after: String\n ) {\n bulkRequestFiles(filterBy: $filterBy, first: $first, after: $after) {\n nodes {\n remoteId\n fileName\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { BULK_REQUEST_FILES } from './gqls/requestFile.js';\n\nexport interface RequestFileCursor {\n /** The ID of the request file */\n id: string;\n /** The created at timestamp */\n createdAt: string;\n}\n\nexport interface RequestFile {\n /** The remote ID */\n remoteId: string;\n /** The file name */\n fileName: string;\n}\n\nexport interface RequestFileResponse {\n /** RequestFiles */\n bulkRequestFiles: {\n /** List */\n nodes: RequestFile[];\n /** The page info */\n pageInfo: {\n /** Whether there is a next page */\n hasNextPage: boolean;\n /** The end cursor */\n endCursor: string;\n };\n };\n}\n\n/**\n * Fetch all RequestFiles for a single request\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All RequestFiles in the organization\n */\nexport async function fetchRequestFilesForRequest(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** How many request files to fetch per API call */\n pageSize?: number;\n /** Filter options */\n filterBy: {\n /** Filter by request IDs */\n requestIds: string[];\n /** Filter by data silo ID */\n dataSiloIds: string[];\n };\n },\n): Promise<RequestFile[]> {\n const { logger, pageSize = 100, filterBy } = options;\n const requestFiles: RequestFile[] = [];\n let cursor: string | null = null;\n\n let shouldContinue = false;\n do {\n const response: RequestFileResponse = await makeGraphQLRequest<RequestFileResponse>(\n client,\n BULK_REQUEST_FILES,\n {\n variables: {\n filterBy: {\n ...filterBy,\n },\n first: pageSize,\n after: cursor ?? undefined,\n },\n logger,\n },\n );\n const {\n bulkRequestFiles: { nodes, pageInfo },\n } = response;\n requestFiles.push(...nodes);\n shouldContinue = pageInfo.hasNextPage;\n cursor = pageInfo.endCursor;\n } while (shouldContinue);\n\n return requestFiles.sort((a, b) => a.remoteId.localeCompare(b.remoteId));\n}\n","export interface DataSiloAttributeValue {\n /** Key associated to value */\n attributeKey: {\n /** Name of key */\n name: string;\n };\n /** Name of value */\n name: string;\n}\n\nexport interface FormattedAttribute {\n /** Attribute key */\n key: string;\n /** Attribute values */\n values: string[];\n}\n\n/**\n * Format attribute value objects to key-pair values\n *\n * @param vals - Attribute values\n * @returns formatted attributes\n */\nexport function formatAttributeValues(vals: DataSiloAttributeValue[]): FormattedAttribute[] {\n const attributes: FormattedAttribute[] = [];\n\n vals.map((val) => {\n let foundKey = attributes.find((att) => att.key === val.attributeKey.name);\n\n if (foundKey === undefined) {\n foundKey = {\n key: val.attributeKey.name,\n values: [val.name],\n };\n attributes.push(foundKey);\n } else {\n foundKey.values.push(val.name);\n }\n return attributes;\n });\n\n return attributes;\n}\n","import { IsoCountryCode, IsoCountrySubdivisionCode } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { difference } from 'lodash-es';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { UPDATE_ACTION } from './gqls/action.js';\n\nconst ALL_COUNTRIES_AND_SUBDIVISIONS = [\n ...Object.values(IsoCountryCode),\n ...Object.values(IsoCountrySubdivisionCode),\n];\n\nexport interface SyncActionInput {\n /** Whether to skip secondary when no files exist */\n skipSecondaryIfNoFiles?: boolean;\n /** Whether to skip downloadable step */\n skipDownloadableStep?: boolean;\n /** Whether the request action requires review */\n requiresReview?: boolean;\n /** The wait period for the action */\n waitingPeriod?: number;\n /** The method in which the data subject's region is detected */\n regionDetectionMethod?: string;\n /** The list of regions to show in the form */\n regionList?: (IsoCountryCode | IsoCountrySubdivisionCode)[];\n /** The list of regions NOT to show in the form */\n regionBlockList?: (IsoCountryCode | IsoCountrySubdivisionCode)[];\n}\n\n/**\n * Sync the consent manager\n *\n * @param client - GraphQL client\n * @param actionInput - Action update details\n * @param options - Options\n */\nexport async function syncAction(\n client: GraphQLClient,\n actionInput: {\n /** Action update input */\n action: SyncActionInput;\n /** Existing action Id */\n actionId: string;\n /** When true, skip publishing to privacy center */\n skipPublish?: boolean;\n },\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n const { logger } = options;\n const { action, actionId, skipPublish = false } = actionInput;\n await makeGraphQLRequest(client, UPDATE_ACTION, {\n variables: {\n input: {\n id: actionId,\n skipSecondaryIfNoFiles: action.skipSecondaryIfNoFiles,\n skipDownloadableStep: action.skipDownloadableStep,\n requiresReview: action.requiresReview,\n waitingPeriod: action.waitingPeriod,\n skipPublish,\n regionList: action.regionBlockList\n ? difference(ALL_COUNTRIES_AND_SUBDIVISIONS, action.regionBlockList)\n : action.regionList,\n regionDetectionMethod: action.regionDetectionMethod,\n },\n },\n logger,\n });\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const TEMPLATES = gql`\n query TranscendCliTemplates($title: String, $first: Int!, $offset: Int!) {\n templates(filterBy: { text: $title }, first: $first, offset: $offset, useMaster: false) {\n nodes {\n id\n title\n subject {\n defaultMessage\n }\n template {\n defaultMessage\n }\n }\n }\n }\n`;\n\nexport const CREATE_TEMPLATE = gql`\n mutation TranscendCliCreateTemplate($title: String!) {\n createTemplate(input: { title: $title, template: \"\", subject: $title }) {\n clientMutationId\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { TEMPLATES, CREATE_TEMPLATE } from './gqls/template.js';\n\nexport interface Template {\n /** ID of Template */\n id: string;\n /** Title of Template */\n title: string;\n /** Template subject (e.g. email subject) */\n subject: {\n /** Default message for template subject */\n defaultMessage: string;\n };\n /** Template body - rich text HTML */\n template: {\n /** Default message for template body */\n defaultMessage: string;\n };\n}\n\nexport interface SyncTemplateInput {\n /** The title of the template */\n title: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all Templates in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All Templates in the organization\n */\nexport async function fetchAllTemplates(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** Filter by title */\n title?: string;\n };\n } = {},\n): Promise<Template[]> {\n const { logger, filterBy: { title } = {} } = options;\n const templates: Template[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n templates: { nodes },\n } = await makeGraphQLRequest<{\n /** Query response */\n templates: {\n /** List of matches */\n nodes: Template[];\n };\n }>(client, TEMPLATES, {\n variables: { first: PAGE_SIZE, offset, title },\n logger,\n });\n templates.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return templates.sort((a, b) => a.title.localeCompare(b.title));\n}\n\n/**\n * Sync an email template configuration\n *\n * @param client - GraphQL client\n * @param template - The email template input\n * @param options - Options\n */\nexport async function syncTemplate(\n client: GraphQLClient,\n template: SyncTemplateInput,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<void> {\n const { logger } = options;\n const matches = await fetchAllTemplates(client, {\n logger,\n filterBy: { title: template.title },\n });\n const existingTemplate = matches.find(({ title }) => title === template.title);\n\n if (!existingTemplate) {\n await makeGraphQLRequest(client, CREATE_TEMPLATE, {\n variables: { title: template.title },\n logger,\n });\n }\n}\n","import { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { ADD_SILO_DISCOVERY_RESULTS } from './gqls/siloDiscovery.js';\n\nexport interface SiloDiscoveryRawResult {\n /** The name of the potential data silo entry */\n name: string;\n /** A unique UUID (represents the same resource across different silo discovery runs) */\n resourceId: string;\n /** Any hosts associated with the entry */\n host?: string;\n /** Type of data silo */\n type?: string | undefined;\n}\n\nconst CHUNK_SIZE = 1000;\n\n/**\n * Uploads silo discovery results for Transcend to classify\n *\n * @param client - GraphQL Client\n * @param options - Options\n */\nexport async function uploadSiloDiscoveryResults(\n client: GraphQLClient,\n options: {\n /** Plugin ID to associate with the results */\n pluginId: string;\n /** The discovery results to upload */\n results: SiloDiscoveryRawResult[];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { pluginId, results, logger = NOOP_LOGGER } = options;\n const chunks = chunk(results, CHUNK_SIZE);\n\n await mapSeries(chunks, async (rawResults) => {\n await makeGraphQLRequest<{\n /** Whether we successfully uploaded the results */\n success: boolean;\n }>(client, ADD_SILO_DISCOVERY_RESULTS, {\n variables: { pluginId, rawResults },\n logger,\n });\n });\n}\n","import { gql } from 'graphql-request';\n\nexport const REPORT_PROMPT_RUN = gql`\n mutation TranscendCliReportPromptRun($input: ReportPromptRunInput!) {\n reportPromptRun(input: $input) {\n clientMutationId\n promptRun {\n id\n }\n }\n }\n`;\n\nexport const ADD_MESSAGES_TO_PROMPT_RUN = gql`\n mutation TranscendCliAddMessagesToPromptRun($input: AddMessagesToPromptRunInput!) {\n addMessagesToPromptRun(input: $input) {\n clientMutationId\n promptRun {\n id\n }\n }\n }\n`;\n","import { QueueStatus, ChatCompletionRole } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { ADD_MESSAGES_TO_PROMPT_RUN } from './gqls/promptRun.js';\n\nexport interface AddMessagesToPromptRunInput {\n /** ID of run */\n promptRunId:\n | {\n /** Report by prompt run name */\n name: string;\n /** Don't report by ID */\n id?: undefined;\n }\n | {\n /** Don't report by name */\n name?: undefined;\n /** Report by prompt run ID */\n id: string;\n };\n /** Messages to report on */\n promptRunMessages?: {\n /** Message reported */\n content: string;\n /** Role of message */\n role: ChatCompletionRole;\n /** Template used if created from prompt */\n template?: string;\n }[];\n /** Error message (if one exists) */\n error?: string;\n /** The status of the run */\n status?: QueueStatus;\n /** Duration of time that it took to execute the prompt */\n duration?: number;\n}\n\n/**\n * Record a new prompt run\n *\n * @param client - GraphQL client\n * @param input - Prompt input\n * @param options - Options\n * @returns Prompt ID\n */\nexport async function addMessagesToPromptRun(\n client: GraphQLClient,\n { promptRunId, promptRunMessages = [], ...rest }: AddMessagesToPromptRunInput,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<string> {\n const { logger } = options;\n const {\n addMessagesToPromptRun: { promptRun },\n } = await makeGraphQLRequest<{\n /** addMessagesToPromptRun mutation */\n addMessagesToPromptRun: {\n /** Prompt */\n promptRun: {\n /** ID */\n id: string;\n };\n };\n }>(client, ADD_MESSAGES_TO_PROMPT_RUN, {\n variables: {\n input: {\n ...rest,\n ...promptRunId,\n promptRunMessages: promptRunMessages.map(({ content, ...rest }) => ({\n ...rest,\n message: content,\n })),\n },\n },\n logger,\n });\n return promptRun.id;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const AGENT_FILES = gql`\n query TranscendCliAgentFiles($first: Int!, $offset: Int!, $filterBy: AgentFileFiltersInput) {\n agentFiles(\n first: $first\n offset: $offset\n filterBy: $filterBy\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n description\n fileId\n size\n purpose\n initialFileName\n }\n }\n }\n`;\n\nexport const CREATE_AGENT_FILE = gql`\n mutation TranscendCliCreateAgentFile($input: CreateAgentFileInput!) {\n createAgentFile(input: $input) {\n agentFile {\n id\n name\n fileId\n initialFileName\n }\n }\n }\n`;\n\nexport const UPDATE_AGENT_FILES = gql`\n mutation TranscendCliUpdateAgentFiles($input: UpdateAgentFilesInput!) {\n updateAgentFiles(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { PromptFilePurpose } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { AGENT_FILES } from './gqls/agentFile.js';\n\nexport interface AgentFile {\n /** ID of agentFile */\n id: string;\n /** Name of agentFile */\n name: string;\n /** Description of the agentFile */\n description: string;\n /** Initial file name, useful to track if a file was split into multiple chunks */\n initialFileName?: string;\n /** File ID */\n fileId: string;\n /** File size */\n size: number;\n /** File purpose */\n purpose: PromptFilePurpose;\n}\n\nexport interface AgentFileFilterBy {\n /** Filter by remote file IDs */\n fileIds?: string[];\n /** Filter by file names */\n names?: string[];\n /** Filter by initial file names (when split into chunks) */\n initialFileNames?: string[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all agent files in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All agent files in the organization\n */\nexport async function fetchAllAgentFiles(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter by */\n filterBy?: AgentFileFilterBy;\n } = {},\n): Promise<AgentFile[]> {\n const { logger, filterBy = {} } = options;\n const agentFiles: AgentFile[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n agentFiles: { nodes },\n } = await makeGraphQLRequest<{\n /** AgentFiles */\n agentFiles: {\n /** List */\n nodes: AgentFile[];\n };\n }>(client, AGENT_FILES, {\n variables: { first: PAGE_SIZE, offset, filterBy },\n logger,\n });\n agentFiles.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return agentFiles.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const AGENT_FUNCTIONS = gql`\n query TranscendCliAgentFunctions($first: Int!, $offset: Int!) {\n agentFunctions(\n first: $first\n offset: $offset\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n description\n parameters\n }\n }\n }\n`;\n\nexport const CREATE_AGENT_FUNCTION = gql`\n mutation TranscendCliCreateAgentFunction($input: CreateAgentFunctionInput!) {\n createAgentFunction(input: $input) {\n agentFunction {\n id\n name\n }\n }\n }\n`;\n\nexport const UPDATE_AGENT_FUNCTIONS = gql`\n mutation TranscendCliUpdateAgentFunctions($input: UpdateAgentFunctionsInput!) {\n updateAgentFunctions(input: $input) {\n clientMutationId\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport type { JSONSchema7 } from 'json-schema';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { AGENT_FUNCTIONS } from './gqls/agentFunction.js';\n\nexport interface AgentFunction {\n /** ID of agentFunction */\n id: string;\n /** Name of agentFunction */\n name: string;\n /** Description of the agentFunction */\n description: string;\n /** The JSON schema */\n parameters: JSONSchema7;\n}\n\ninterface AgentFunctionRaw extends Omit<AgentFunction, 'parameters'> {\n /** Stringified parameters */\n parameters: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all agent functions in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All agent functions in the organization\n */\nexport async function fetchAllAgentFunctions(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<AgentFunction[]> {\n const { logger } = options;\n const agentFunctions: AgentFunction[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n agentFunctions: { nodes },\n } = await makeGraphQLRequest<{\n /** AgentFunctions */\n agentFunctions: {\n /** List */\n nodes: AgentFunctionRaw[];\n };\n }>(client, AGENT_FUNCTIONS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n agentFunctions.push(\n ...nodes.map((node) => ({\n ...node,\n parameters: JSON.parse(node.parameters),\n })),\n );\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return agentFunctions.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const AGENTS = gql`\n query TranscendCliAgents($first: Int!, $offset: Int!, $filterBy: AgentFiltersInput) {\n agents(\n first: $first\n offset: $offset\n filterBy: $filterBy\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n agentId\n instructions\n description\n codeInterpreterEnabled\n retrievalEnabled\n prompt {\n title\n }\n largeLanguageModel {\n name\n client\n }\n teams {\n name\n }\n owners {\n email\n }\n agentFunctions {\n name\n }\n agentFiles {\n name\n }\n }\n }\n }\n`;\n\nexport const CREATE_AGENT = gql`\n mutation TranscendCliCreateAgent($input: CreateAgentInput!) {\n createAgent(input: $input) {\n agent {\n id\n name\n agentId\n }\n }\n }\n`;\n\nexport const UPDATE_AGENTS = gql`\n mutation TranscendCliUpdateAgents($input: UpdateAgentsInput!) {\n updateAgents(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { LargeLanguageModelClient } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { AGENTS } from './gqls/agent.js';\n\nexport interface Agent {\n /** ID of agent */\n id: string;\n /** Name of agent */\n name: string;\n /** Agent instructions */\n instructions: string;\n /** The ID of the agent */\n agentId: string;\n /** Description of the agent */\n description: string;\n /** Whether the agent has code interpreter enabled */\n codeInterpreterEnabled: boolean;\n /** Whether the agent has retrieval enabled */\n retrievalEnabled: boolean;\n /** The prompt that the agent is based on */\n prompt?: {\n /** Title of the prompt */\n title: string;\n };\n /** Large language model that the agent is based on */\n largeLanguageModel: {\n /** Name of model */\n name: string;\n /** Client */\n client: LargeLanguageModelClient;\n };\n /** Teams assigned to the agent */\n teams: {\n /** Team name */\n name: string;\n }[];\n /** Users assigned to the agent */\n owners: {\n /** User email */\n email: string;\n }[];\n /** Functions that the agent has access to */\n agentFunctions: {\n /** Function name */\n name: string;\n }[];\n /** Files that the agent has access to */\n agentFiles: {\n /** File name */\n name: string;\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all agents in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All agents in the organization\n */\nexport async function fetchAllAgents(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter by */\n filterBy?: {\n /** Names of the agents to filter for */\n names?: string[];\n /** IDs of agents */\n agentIds?: string[];\n };\n } = {},\n): Promise<Agent[]> {\n const { logger, filterBy = {} } = options;\n const agents: Agent[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n agents: { nodes },\n } = await makeGraphQLRequest<{\n /** Agents */\n agents: {\n /** List */\n nodes: Agent[];\n };\n }>(client, AGENTS, {\n variables: { first: PAGE_SIZE, offset, filterBy },\n logger,\n });\n agents.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return agents.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const LARGE_LANGUAGE_MODELS = gql`\n query TranscendCliLargeLanguageModels(\n $first: Int!\n $offset: Int!\n $filterBy: LargeLanguageModelFiltersInput\n ) {\n largeLanguageModels(\n first: $first\n orderBy: [\n { field: name, direction: ASC }\n { field: client, direction: ASC }\n { field: isTranscendHosted, direction: ASC }\n ]\n offset: $offset\n filterBy: $filterBy\n ) {\n nodes {\n id\n name\n client\n isTranscendHosted\n }\n }\n }\n`;\n","import { LargeLanguageModelClient } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { LARGE_LANGUAGE_MODELS } from './gqls/largeLanguageModel.js';\n\nexport interface LargeLanguageModel {\n /** ID of prompts */\n id: string;\n /** The name of the large language model. */\n name: string;\n /** The content of the prompt template. */\n client: LargeLanguageModelClient;\n /** Whether hosted by Transcend or not */\n isTranscendHosted: boolean;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all LargeLanguageModels in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All LargeLanguageModels in the organization\n */\nexport async function fetchAllLargeLanguageModels(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<LargeLanguageModel[]> {\n const { logger } = options;\n const largeLanguageModels: LargeLanguageModel[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n largeLanguageModels: { nodes },\n } = await makeGraphQLRequest<{\n /** LargeLanguageModels */\n largeLanguageModels: {\n /** List */\n nodes: LargeLanguageModel[];\n };\n }>(client, LARGE_LANGUAGE_MODELS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n largeLanguageModels.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return largeLanguageModels.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const PROMPTS = gql`\n query TranscendCliPrompts($first: Int!, $offset: Int!, $filterBy: PromptFiltersInput) {\n prompts(\n first: $first\n orderBy: [{ field: title, direction: ASC }]\n offset: $offset\n filterBy: $filterBy\n ) {\n nodes {\n id\n title\n status\n content\n temperature\n topP\n maxTokensToSample\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\n// orderBy: [{ field: title, direction: ASC }]\nexport const PROMPT_PARTIALS = gql`\n query TranscendCliPromptPartials($first: Int!, $offset: Int!) {\n promptPartials(first: $first, offset: $offset) {\n nodes {\n id\n title\n content\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\n// TODO: https://transcend.height.app/T-27909 - order by createdAt\n// orderBy: [{ field: title, direction: ASC }]\nexport const PROMPT_GROUPS = gql`\n query TranscendCliPromptGroups($first: Int!, $offset: Int!) {\n promptGroups(first: $first, offset: $offset) {\n nodes {\n id\n title\n description\n prompts {\n title\n }\n }\n }\n }\n`;\n\nexport const PROMPTS_WITH_VARIABLES = gql`\n query TranscendCliPromptsWithVariables($input: PromptsWithVariablesInput!) {\n promptsWithVariables(input: $input) {\n prompts {\n id\n title\n content\n status\n temperature\n topP\n maxTokensToSample\n responseFormat\n }\n promptPartials {\n id\n title\n content\n slug\n }\n calculatedVariables {\n data\n name\n }\n runtimeVariables {\n name\n }\n }\n }\n`;\n\nexport const UPDATE_PROMPTS = gql`\n mutation TranscendCliUpdatePrompts($input: UpdatePromptsInput!) {\n updatePrompts(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const CREATE_PROMPT = gql`\n mutation TranscendCliCreatePrompt($input: CreatePromptInput!) {\n createPrompt(input: $input) {\n clientMutationId\n prompt {\n id\n }\n }\n }\n`;\n\nexport const UPDATE_PROMPT_PARTIALS = gql`\n mutation TranscendCliUpdatePromptPartials($input: UpdatePromptPartialsInput!) {\n updatePromptPartials(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const CREATE_PROMPT_PARTIAL = gql`\n mutation TranscendCliCreatePromptPartial($input: CreatePromptPartialInput!) {\n createPromptPartial(input: $input) {\n clientMutationId\n promptPartial {\n id\n }\n }\n }\n`;\n\nexport const UPDATE_PROMPT_GROUPS = gql`\n mutation TranscendCliUpdatePromptGroups($input: UpdatePromptGroupsInput!) {\n updatePromptGroups(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const CREATE_PROMPT_GROUP = gql`\n mutation TranscendCliCreatePromptPartial($input: CreatePromptGroupInput!) {\n createPromptGroup(input: $input) {\n clientMutationId\n promptGroup {\n id\n }\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PROMPT_GROUPS } from './gqls/prompt.js';\n\nexport interface PromptGroup {\n /** ID of prompts */\n id: string;\n /** The title of the prompt group. */\n title: string;\n /** The description of the prompt group. */\n description: string;\n /** Prompts in the group */\n prompts: {\n /** Title of prompt */\n title: string;\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all PromptGroups in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All PromptGroups in the organization\n */\nexport async function fetchAllPromptGroups(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<PromptGroup[]> {\n const { logger } = options;\n const promptGroups: PromptGroup[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n promptGroups: { nodes },\n } = await makeGraphQLRequest<{\n /** PromptGroups */\n promptGroups: {\n /** List */\n nodes: PromptGroup[];\n };\n }>(client, PROMPT_GROUPS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n promptGroups.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return promptGroups.sort((a, b) => a.title.localeCompare(b.title));\n}\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PROMPT_PARTIALS } from './gqls/prompt.js';\n\nexport interface PromptPartial {\n /** ID of prompts */\n id: string;\n /** The title of the prompt partial. */\n title: string;\n /** The content of the prompt partial. */\n content: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all PromptPartials in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All PromptPartials in the organization\n */\nexport async function fetchAllPromptPartials(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<PromptPartial[]> {\n const { logger } = options;\n const promptPartials: PromptPartial[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n promptPartials: { nodes },\n } = await makeGraphQLRequest<{\n /** PromptPartials */\n promptPartials: {\n /** List */\n nodes: PromptPartial[];\n };\n }>(client, PROMPT_PARTIALS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n promptPartials.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return promptPartials.sort((a, b) => a.title.localeCompare(b.title));\n}\n","import { PromptStatus, PromptResponseFormat } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PROMPTS, PROMPTS_WITH_VARIABLES } from './gqls/prompt.js';\n\nexport interface Prompt {\n /** ID of prompt */\n id: string;\n /** The title of the prompt */\n title: string;\n /** The status of the prompt */\n status: PromptStatus;\n /** The content of the prompt */\n content: string;\n /** Temperature to use with prompt */\n temperature: number;\n /** Top P to use with prompt */\n topP: number;\n /** Max tokens to sample for prompt */\n maxTokensToSample: number;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all Prompts in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All Prompts in the organization\n */\nexport async function fetchAllPrompts(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** Filter by text */\n text?: string;\n /** Filter by ids */\n ids?: string[];\n /** Filter by titles */\n titles?: string[];\n };\n } = {},\n): Promise<Prompt[]> {\n const { logger, filterBy: { text, ids = [], titles = [] } = {} } = options;\n const prompts: Prompt[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n prompts: { nodes },\n } = await makeGraphQLRequest<{\n /** Prompts */\n prompts: {\n /** List */\n nodes: Prompt[];\n };\n }>(client, PROMPTS, {\n variables: {\n first: PAGE_SIZE,\n offset,\n filterBy: {\n ...(text ? { text } : {}),\n ...(titles.length > 0 ? { title: titles } : {}),\n ...(ids.length > 0 ? { id: ids } : {}),\n },\n },\n logger,\n });\n prompts.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return prompts.sort((a, b) => a.title.localeCompare(b.title));\n}\n\n/**\n * The basic metadata needed to use a prompt at runtime\n */\nexport type TranscendPromptTemplated = {\n /** ID of prompt */\n id: string;\n /** Title of prompt */\n title: string;\n /** Content of prompt */\n content: string;\n /** Status of prompt */\n status: PromptStatus;\n /** Temperature */\n temperature?: number;\n /** Top P */\n topP?: number;\n /** Max tokens to sample */\n maxTokensToSample?: number;\n /** Response format */\n responseFormat?: PromptResponseFormat;\n};\n\n/**\n * The basic metadata needed to use a prompt partial at runtime\n */\nexport type TranscendPromptPartialTemplated = {\n /** ID of prompt */\n id: string;\n /** Title of prompt */\n title: string;\n /** Slug of prompt */\n slug: string;\n /** Content of prompt */\n content: string;\n};\n\n/**\n * Calculated variables\n */\nexport type PromptCalculatedVariable = {\n /** JSON stringified data to template */\n data: string | null;\n /** Name of variable */\n name: string;\n};\n\n/**\n * Runtime variables\n */\nexport type PromptRuntimeVariable = {\n /** Type of variable */\n type: string;\n /** Name of variable */\n name: string;\n};\n\n/**\n * Metadata useful for filling variables within a prompt\n */\nexport type TranscendPromptsAndVariables = {\n /** Prompts ready to be templated */\n prompts: TranscendPromptTemplated[];\n /** Prompt partials */\n promptPartials: TranscendPromptPartialTemplated[];\n /** Calculated variables to be templated */\n calculatedVariables: PromptCalculatedVariable[];\n /** Runtime variables to be templated */\n runtimeVariables: PromptRuntimeVariable[];\n};\n\n/**\n * Fetch prompts with templated variables\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Prompts and template variables\n */\nexport async function fetchPromptsWithVariables(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy?: {\n /** Filter by prompt titles */\n titles?: string[];\n /** Filter by prompt ids */\n ids?: string[];\n };\n } = {},\n): Promise<TranscendPromptsAndVariables> {\n const { logger, filterBy: { titles: promptTitles = [], ids: promptIds = [] } = {} } = options;\n const { promptsWithVariables } = await makeGraphQLRequest<{\n /** Prompts */\n promptsWithVariables: TranscendPromptsAndVariables;\n }>(client, PROMPTS_WITH_VARIABLES, {\n variables: {\n input: {\n ...(promptTitles.length > 0 ? { promptTitles } : {}),\n ...(promptIds.length > 0 ? { promptIds } : {}),\n },\n },\n logger,\n });\n\n return promptsWithVariables;\n}\n","import { gql } from 'graphql-request';\n\nexport const PROMPT_THREADS = gql`\n query TranscendCliPromptThreads(\n $first: Int!\n $offset: Int!\n $filterBy: PromptThreadFiltersInput!\n ) {\n promptThreads(first: $first, offset: $offset, filterBy: $filterBy) {\n nodes {\n id\n threadId\n slackMessageTs\n slackTeamId\n slackChannelId\n slackChannelName\n }\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PROMPT_THREADS } from './gqls/promptThread.js';\n\nexport interface PromptThread {\n /** ID of prompts */\n id: string;\n /** Thread ID from API */\n threadId: string;\n /** Related slack message TS */\n slackMessageTs?: string;\n /** Related slack message team ID */\n slackTeamId?: string;\n /** Related slack channel ID */\n slackChannelId?: string;\n /** Related slack channel name */\n slackChannelName?: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all PromptThreads in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All PromptThreads in the organization\n */\nexport async function fetchAllPromptThreads(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter options */\n filterBy: {\n /** Thread IDs to filter on */\n threadIds?: string[];\n /** Slack message timestamps to filter on */\n slackMessageTs?: string[];\n };\n },\n): Promise<PromptThread[]> {\n const { logger, filterBy } = options;\n const promptThreads: PromptThread[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n promptThreads: { nodes },\n } = await makeGraphQLRequest<{\n /** PromptThreads */\n promptThreads: {\n /** List */\n nodes: PromptThread[];\n };\n }>(client, PROMPT_THREADS, {\n variables: { first: PAGE_SIZE, offset, filterBy },\n logger,\n });\n promptThreads.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return promptThreads.sort((a, b) => a.threadId.localeCompare(b.threadId));\n}\n","import {\n QueueStatus,\n ChatCompletionRole,\n PromptRunProductArea,\n LargeLanguageModelClient,\n} from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { REPORT_PROMPT_RUN } from './gqls/promptRun.js';\n\nexport interface ReportPromptRunInput {\n /** Name of run */\n name: string;\n /** The related product area being uploaded to */\n productArea: PromptRunProductArea;\n /** Messages reported on */\n promptRunMessages: {\n /** Message reported */\n content: string;\n /** Role of message */\n role: ChatCompletionRole;\n /** Template used if created from prompt */\n template?: string;\n }[];\n /** ID of the Transcend prompt being reported */\n promptId?: string;\n /** Title of the prompt being reported on */\n promptTitle?: string;\n /** Error message (if one exists) */\n error?: string;\n /** The status of the run */\n status?: QueueStatus;\n /** Employee email that is executing the request */\n runByEmployeeEmail?: string;\n /** Duration of time that it took to execute the prompt */\n duration?: number;\n /** Temperature used when running prompt */\n temperature?: number;\n /** TopP parameter used when running prompt */\n topP?: number;\n /** Max tokens ot sample parameter used when running prompt */\n maxTokensToSample?: number;\n /** The ID of the prompt group being reported */\n promptGroupId?: string;\n /** The title of the prompt group being reported */\n promptGroupTitle?: string;\n /** The LLM Id being reported on */\n largeLanguageModelId?: string;\n /** The name of the large language model being reported on */\n largeLanguageModelName?: string;\n /** The name of the large language model client reported on */\n largeLanguageModelClient?: LargeLanguageModelClient;\n /** ID of the application calling pathfinder */\n applicationId?: string;\n /** Name of the application calling pathfinder */\n applicationName?: string;\n /** Name of the code package calling pathfinder */\n codePackageName?: string;\n /** Name of the repository calling pathfinder */\n repositoryName?: string;\n /** ID of the pathfinder applying policies */\n pathfinderId?: string;\n /** Name of the pathfinder applying policies */\n pathfinderName?: string;\n /** Core identifier of the application user being reported on */\n applicationUserCoreIdentifier?: string;\n /** Name of the application user being reported on */\n applicationUserName?: string;\n}\n\n/**\n * Record a new prompt run\n *\n * @param client - GraphQL client\n * @param input - Prompt input\n * @param options - Options\n * @returns Prompt ID\n */\nexport async function reportPromptRun(\n client: GraphQLClient,\n input: ReportPromptRunInput,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<string> {\n const { logger } = options;\n const {\n reportPromptRun: { promptRun },\n } = await makeGraphQLRequest<{\n /** reportPromptRun mutation */\n reportPromptRun: {\n /** Prompt */\n promptRun: {\n /** ID */\n id: string;\n };\n };\n }>(client, REPORT_PROMPT_RUN, {\n variables: {\n input: {\n ...input,\n promptRunMessages: input.promptRunMessages.map(({ content, ...rest }) => ({\n ...rest,\n message: content,\n })),\n },\n },\n logger,\n });\n return promptRun.id;\n}\n","import { PromptFilePurpose } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllAgentFiles, type AgentFile } from './fetchAllAgentFiles.js';\nimport { UPDATE_AGENT_FILES, CREATE_AGENT_FILE } from './gqls/agentFile.js';\n\nexport interface AgentFileInput {\n /** Name of the agent file */\n name: string;\n /** Description of the agent file */\n description?: string;\n /** File ID */\n fileId: string;\n /** File size */\n size: number;\n /** File purpose */\n purpose: PromptFilePurpose;\n}\n\n/**\n * Create a new agent file\n *\n * @param client - GraphQL client\n * @param agentFile - Input\n * @param options - Options\n * @returns Created agent file\n */\nexport async function createAgentFile(\n client: GraphQLClient,\n options: {\n /** Agent file to create */\n input: AgentFileInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<AgentFile, 'id' | 'name' | 'fileId'>> {\n const { input: agentFile, logger = NOOP_LOGGER } = options;\n const input = {\n name: agentFile.name,\n description: agentFile.description,\n fileId: agentFile.fileId,\n size: agentFile.size,\n purpose: agentFile.purpose,\n fileUploadedAt: new Date(),\n agentIds: [],\n // TODO: https://transcend.height.app/T-31994 - sync agents\n };\n\n const { createAgentFile } = await makeGraphQLRequest<{\n /** Create agent file mutation */\n createAgentFile: {\n /** Created agent file */\n agentFile: AgentFile;\n };\n }>(client, CREATE_AGENT_FILE, {\n variables: { input },\n logger,\n });\n return createAgentFile.agentFile;\n}\n\n/**\n * Update agent files\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateAgentFiles(\n client: GraphQLClient,\n options: {\n /** [AgentFileInput, agentFileId] list */\n input: [AgentFileInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: agentFiles, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_AGENT_FILES, {\n variables: {\n input: {\n agentFiles: agentFiles.map(([agentFile, id]) => ({\n id,\n name: agentFile.name,\n description: agentFile.description,\n fileId: agentFile.fileId,\n size: agentFile.size,\n purpose: agentFile.purpose,\n })),\n },\n },\n logger,\n });\n}\n\n/**\n * Sync the agent files\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncAgentFiles(\n client: GraphQLClient,\n inputs: AgentFileInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n logger.info(`Syncing \"${inputs.length}\" agent files...`);\n\n let encounteredError = false;\n\n const existingAgentFiles = await fetchAllAgentFiles(client, { logger });\n\n const agentFileByName = keyBy(existingAgentFiles, 'name') as {\n [k in string]: Pick<AgentFile, 'id' | 'name' | 'fileId'>;\n };\n\n const newAgentFiles = inputs.filter((input) => !agentFileByName[input.name]);\n\n await mapSeries(newAgentFiles, async (agentFile) => {\n try {\n const newAgentFile = await createAgentFile(client, { input: agentFile, logger });\n agentFileByName[newAgentFile.name] = newAgentFile;\n logger.info(`Successfully synced agent file \"${agentFile.name}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync agent file \"${agentFile.name}\"! - ${(err as Error).message}`);\n }\n });\n\n try {\n logger.info(`Updating \"${inputs.length}\" agent files!`);\n await updateAgentFiles(client, {\n input: inputs.map((input) => [input, agentFileByName[input.name]!.id]),\n logger,\n });\n logger.info(`Successfully synced \"${inputs.length}\" agent files!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync \"${inputs.length}\" agent files! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport type { JSONSchema7 } from 'json-schema';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllAgentFunctions, type AgentFunction } from './fetchAllAgentFunctions.js';\nimport { UPDATE_AGENT_FUNCTIONS, CREATE_AGENT_FUNCTION } from './gqls/agentFunction.js';\n\nexport interface AgentFunctionInput {\n /** Name of the agent function */\n name: string;\n /** Description of the agent function */\n description: string;\n /** The JSON schema parameters (string or parsed) */\n parameters: JSONSchema7 | string;\n}\n\n/**\n * Create a new agent function\n *\n * @param client - GraphQL client\n * @param agentFunction - Input\n * @param options - Options\n * @returns Created agent function\n */\nexport async function createAgentFunction(\n client: GraphQLClient,\n options: {\n /** Agent function to create */\n input: AgentFunctionInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<AgentFunction, 'id' | 'name'>> {\n const { input: agentFunction, logger = NOOP_LOGGER } = options;\n const input = {\n name: agentFunction.name,\n description: agentFunction.description,\n parameters: agentFunction.parameters,\n agentIds: [],\n // TODO: https://transcend.height.app/T-31994 - sync agents\n };\n\n const { createAgentFunction } = await makeGraphQLRequest<{\n /** Create agent function mutation */\n createAgentFunction: {\n /** Created agent function */\n agentFunction: AgentFunction;\n };\n }>(client, CREATE_AGENT_FUNCTION, {\n variables: { input },\n logger,\n });\n return createAgentFunction.agentFunction;\n}\n\n/**\n * Update agent functions\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateAgentFunctions(\n client: GraphQLClient,\n options: {\n /** [AgentFunctionInput, agentFunctionId] list */\n input: [AgentFunctionInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: agentFunctions, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_AGENT_FUNCTIONS, {\n variables: {\n input: {\n agentFunctions: agentFunctions.map(([agentFunction, id]) => ({\n id,\n name: agentFunction.name,\n description: agentFunction.description,\n parameters: agentFunction.parameters,\n })),\n },\n },\n logger,\n });\n}\n\n/**\n * Sync the agent functions\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncAgentFunctions(\n client: GraphQLClient,\n inputs: AgentFunctionInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n logger.info(`Syncing \"${inputs.length}\" agent functions...`);\n\n let encounteredError = false;\n\n const existingAgentFunctions = await fetchAllAgentFunctions(client, { logger });\n\n const agentFunctionByName = keyBy(existingAgentFunctions, 'name') as {\n [k in string]: Pick<AgentFunction, 'id' | 'name'>;\n };\n\n const newAgentFunctions = inputs.filter((input) => !agentFunctionByName[input.name]);\n\n await mapSeries(newAgentFunctions, async (agentFunction) => {\n try {\n const newAgentFunction = await createAgentFunction(client, { input: agentFunction, logger });\n agentFunctionByName[newAgentFunction.name] = newAgentFunction;\n logger.info(`Successfully synced agent function \"${agentFunction.name}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to sync agent function \"${agentFunction.name}\"! - ${(err as Error).message}`,\n );\n }\n });\n\n try {\n logger.info(`Updating \"${inputs.length}\" agent functions!`);\n await updateAgentFunctions(client, {\n input: inputs.map((input) => [input, agentFunctionByName[input.name]!.id]),\n logger,\n });\n logger.info(`Successfully synced \"${inputs.length}\" agent functions!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync \"${inputs.length}\" agent functions! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import { LargeLanguageModelClient } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllAgents, type Agent } from './fetchAllAgents.js';\nimport { UPDATE_AGENTS, CREATE_AGENT } from './gqls/agent.js';\n\nexport interface AgentInput {\n /** Name of the agent */\n name: string;\n /** Description of the agent */\n description?: string;\n /** Whether the agent has code interpreter enabled */\n codeInterpreterEnabled?: boolean;\n /** Whether the agent has retrieval enabled */\n retrievalEnabled?: boolean;\n /** The prompt title */\n prompt?: string;\n /** Large language model config */\n 'large-language-model': {\n /** Name of model */\n name: string;\n /** Client */\n client: LargeLanguageModelClient;\n };\n}\n\n/**\n * Create a new agent\n *\n * @param client - GraphQL client\n * @param agent - Input\n * @param options - Options\n * @returns Created agent\n */\nexport async function createAgent(\n client: GraphQLClient,\n options: {\n /** Agent to create */\n input: AgentInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<Agent, 'id' | 'name' | 'agentId'>> {\n const { input: agent, logger = NOOP_LOGGER } = options;\n const input = {\n name: agent.name,\n description: agent.description,\n codeInterpreterEnabled: agent.codeInterpreterEnabled,\n retrievalEnabled: agent.retrievalEnabled,\n promptTitle: agent.prompt,\n largeLanguageModelName: agent['large-language-model'].name,\n largeLanguageModelClient: agent['large-language-model'].client,\n // TODO: https://transcend.height.app/T-32760 - agentFunction, agentFile\n // TODO: https://transcend.height.app/T-31994 - owners and teams\n };\n\n const { createAgent } = await makeGraphQLRequest<{\n /** Create agent mutation */\n createAgent: {\n /** Created agent */\n agent: Agent;\n };\n }>(client, CREATE_AGENT, {\n variables: { input },\n logger,\n });\n return createAgent.agent;\n}\n\n/**\n * Update agents\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateAgents(\n client: GraphQLClient,\n options: {\n /** [AgentInput, agentId] list */\n input: [AgentInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: agents, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_AGENTS, {\n variables: {\n input: {\n agents: agents.map(([agent, id]) => ({\n id,\n name: agent.name,\n description: agent.description,\n codeInterpreterEnabled: agent.codeInterpreterEnabled,\n retrievalEnabled: agent.retrievalEnabled,\n // TODO: https://transcend.height.app/T-31995 - prompt, largeLanguageModel, agentFunction, agentFile\n })),\n },\n },\n logger,\n });\n}\n\n/**\n * Sync the agents\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncAgents(\n client: GraphQLClient,\n inputs: AgentInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n logger.info(`Syncing \"${inputs.length}\" agents...`);\n\n let encounteredError = false;\n\n const existingAgents = await fetchAllAgents(client, { logger });\n\n const agentByName = keyBy(existingAgents, 'name') as {\n [k in string]: Pick<Agent, 'id' | 'name' | 'agentId'>;\n };\n\n const newAgents = inputs.filter((input) => !agentByName[input.name]);\n\n await mapSeries(newAgents, async (agent) => {\n try {\n const newAgent = await createAgent(client, { input: agent, logger });\n agentByName[newAgent.name] = newAgent;\n logger.info(`Successfully synced agent \"${agent.name}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync agent \"${agent.name}\"! - ${(err as Error).message}`);\n }\n });\n\n try {\n logger.info(`Updating \"${inputs.length}\" agents!`);\n await updateAgents(client, {\n input: inputs.map((input) => [input, agentByName[input.name]!.id]),\n logger,\n });\n logger.info(`Successfully synced \"${inputs.length}\" agents!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync \"${inputs.length}\" agents! - ${(err as Error).message}`);\n }\n\n return !encounteredError;\n}\n","import { map, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllPromptGroups } from './fetchPromptGroups.js';\nimport { fetchAllPrompts } from './fetchPrompts.js';\nimport { UPDATE_PROMPT_GROUPS, CREATE_PROMPT_GROUP } from './gqls/prompt.js';\n\nexport interface PromptGroupInput {\n /** Title of prompt group */\n title: string;\n /** Description */\n description: string;\n /** Prompt titles */\n prompts: string[];\n}\n\nexport interface EditPromptGroupInput {\n /** Title of prompt group */\n title: string;\n /** Prompt group description */\n description: string;\n /** Prompt IDs */\n promptIds: string[];\n}\n\n/**\n * Create a new prompt group\n *\n * @param client - GraphQL client\n * @param input - Prompt input\n * @param options - Options\n * @returns Prompt group ID\n */\nexport async function createPromptGroup(\n client: GraphQLClient,\n options: {\n /** Prompt group to create */\n input: EditPromptGroupInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<string> {\n const { input, logger = NOOP_LOGGER } = options;\n const {\n createPromptGroup: { promptGroup },\n } = await makeGraphQLRequest<{\n /** createPromptGroup mutation */\n createPromptGroup: {\n /** Prompt group */\n promptGroup: {\n /** ID */\n id: string;\n };\n };\n }>(client, CREATE_PROMPT_GROUP, {\n variables: { input },\n logger,\n });\n logger.info(`Successfully created prompt group \"${input.title}\"!`);\n return promptGroup.id;\n}\n\n/**\n * Update a set of existing prompt groups\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updatePromptGroups(\n client: GraphQLClient,\n options: {\n /** [EditPromptGroupInput, promptGroupId] list */\n input: [EditPromptGroupInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: promptGroups, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_PROMPT_GROUPS, {\n variables: {\n input: {\n promptGroups: promptGroups.map(([promptGroup, id]) => ({\n ...promptGroup,\n id,\n })),\n },\n },\n logger,\n });\n logger.info(`Successfully updated ${promptGroups.length} prompt groups!`);\n}\n\n/**\n * Sync the prompt groups\n *\n * @param client - GraphQL client\n * @param promptGroups - PromptGroups\n * @param options - Options\n * @returns True if synced successfully\n */\nexport async function syncPromptGroups(\n client: GraphQLClient,\n promptGroups: PromptGroupInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Concurrency */\n concurrency?: number;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER, concurrency = 20 } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${promptGroups.length}\" prompt groups...`);\n\n // Index existing prompt groups\n const existing = await fetchAllPromptGroups(client, { logger });\n const existingPrompts = await fetchAllPrompts(client, { logger });\n const promptByTitle = keyBy(existingPrompts, 'title');\n const promptGroupByTitle = keyBy(existing, 'title');\n\n // Determine which promptGroups are new vs existing\n const mapPromptGroupsToExisting = promptGroups.map((promptInput) => [\n promptInput,\n promptGroupByTitle[promptInput.title]?.id,\n ]);\n\n // Create the new promptGroups\n const newPromptGroups = mapPromptGroupsToExisting\n .filter(([, existing]) => !existing)\n .map(([promptInput]) => promptInput as PromptGroupInput);\n try {\n logger.info(`Creating \"${newPromptGroups.length}\" new prompt groups...`);\n await map(\n newPromptGroups,\n async (prompt) => {\n await createPromptGroup(client, {\n input: {\n ...prompt,\n promptIds: prompt.prompts.map((title) => {\n const prompt = promptByTitle[title];\n if (!prompt) {\n throw new Error(`Failed to find prompt with title: \"${title}\"`);\n }\n return prompt.id;\n }),\n },\n logger,\n });\n },\n {\n concurrency,\n },\n );\n logger.info(`Successfully synced ${newPromptGroups.length} prompt groups!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create prompt groups! - ${(err as Error).message}`);\n }\n\n // Update existing promptGroups\n const existingPromptGroupsMapped = mapPromptGroupsToExisting.filter(\n (x): x is [PromptGroupInput, string] => !!x[1],\n );\n try {\n logger.info(`Updating \"${existingPromptGroupsMapped.length}\" prompt groups...`);\n await updatePromptGroups(client, {\n input: existingPromptGroupsMapped.map(([{ prompts, ...input }, id]) => [\n {\n ...input,\n promptIds: prompts.map((title) => {\n const prompt = promptByTitle[title];\n if (!prompt) {\n throw new Error(`Failed to find prompt with title: \"${title}\"`);\n }\n return prompt.id;\n }),\n },\n id,\n ]),\n logger,\n });\n logger.info(`Successfully updated \"${existingPromptGroupsMapped.length}\" prompt groups!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create prompt groups! - ${(err as Error).message}`);\n }\n\n logger.info(`Synced \"${promptGroups.length}\" prompt groups!`);\n\n return !encounteredError;\n}\n","import { map, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllPromptPartials } from './fetchPromptPartials.js';\nimport { UPDATE_PROMPT_PARTIALS, CREATE_PROMPT_PARTIAL } from './gqls/prompt.js';\n\nexport interface PromptPartialInput {\n /** Title of prompt partial */\n title: string;\n /** Prompt partial content */\n content: string;\n}\n\n/**\n * Create a new prompt partial\n *\n * @param client - GraphQL client\n * @param input - Prompt input\n * @param options - Options\n * @returns Prompt partial ID\n */\nexport async function createPromptPartial(\n client: GraphQLClient,\n options: {\n /** Prompt partial to create */\n input: {\n /** Title of prompt partial */\n title: string;\n /** Prompt content */\n content: string;\n };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<string> {\n const { input, logger = NOOP_LOGGER } = options;\n const {\n createPromptPartial: { promptPartial },\n } = await makeGraphQLRequest<{\n /** createPromptPartial mutation */\n createPromptPartial: {\n /** Prompt partial */\n promptPartial: {\n /** ID */\n id: string;\n };\n };\n }>(client, CREATE_PROMPT_PARTIAL, {\n variables: { input },\n logger,\n });\n logger.info(`Successfully created prompt partial \"${input.title}\"!`);\n return promptPartial.id;\n}\n\n/**\n * Update a set of existing prompt partials\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updatePromptPartials(\n client: GraphQLClient,\n options: {\n /** [PromptPartialInput, promptPartialId] list */\n input: [PromptPartialInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: promptPartials, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_PROMPT_PARTIALS, {\n variables: {\n input: {\n promptPartials: promptPartials.map(([promptPartial, id]) => ({\n ...promptPartial,\n id,\n })),\n },\n },\n logger,\n });\n logger.info(`Successfully updated ${promptPartials.length} prompt partials!`);\n}\n\n/**\n * Sync the prompt partials\n *\n * @param client - GraphQL client\n * @param promptPartials - PromptPartials\n * @param options - Options\n * @returns True if synced successfully\n */\nexport async function syncPromptPartials(\n client: GraphQLClient,\n promptPartials: PromptPartialInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Concurrency */\n concurrency?: number;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER, concurrency = 20 } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${promptPartials.length}\" prompt partials...`);\n\n // Index existing prompt partials\n const existing = await fetchAllPromptPartials(client, { logger });\n const promptPartialByTitle = keyBy(existing, 'title');\n\n // Determine which promptPartials are new vs existing\n const mapPromptPartialsToExisting = promptPartials.map((promptInput) => [\n promptInput,\n promptPartialByTitle[promptInput.title]?.id,\n ]);\n\n // Create the new promptPartials\n const newPromptPartials = mapPromptPartialsToExisting\n .filter(([, existing]) => !existing)\n .map(([promptInput]) => promptInput as PromptPartialInput);\n try {\n logger.info(`Creating \"${newPromptPartials.length}\" new prompt partials...`);\n await map(\n newPromptPartials,\n async (prompt) => {\n await createPromptPartial(client, { input: prompt, logger });\n },\n {\n concurrency,\n },\n );\n logger.info(`Successfully synced ${newPromptPartials.length} prompt partials!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create prompt partials! - ${(err as Error).message}`);\n }\n\n // Update existing promptPartials\n const existingPromptPartials = mapPromptPartialsToExisting.filter(\n (x): x is [PromptPartialInput, string] => !!x[1],\n );\n try {\n logger.info(`Updating \"${existingPromptPartials.length}\" prompt partials...`);\n await updatePromptPartials(client, { input: existingPromptPartials, logger });\n logger.info(`Successfully updated \"${existingPromptPartials.length}\" prompt partials!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create prompt partials! - ${(err as Error).message}`);\n }\n\n logger.info(`Synced \"${promptPartials.length}\" prompt partials!`);\n\n return !encounteredError;\n}\n","import { map, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllPrompts } from './fetchPrompts.js';\nimport { UPDATE_PROMPTS, CREATE_PROMPT } from './gqls/prompt.js';\n\nexport interface PromptInput {\n /** Title of prompt */\n title: string;\n /** Prompt content */\n content: string;\n /** Status */\n status?: string;\n /** Temperature */\n temperature?: number;\n /** Top P */\n topP?: number;\n /** Max tokens to sample */\n maxTokensToSample?: number;\n}\n\n/**\n * Create a new prompt\n *\n * @param client - GraphQL client\n * @param input - Prompt input\n * @param options - Options\n * @returns Prompt ID\n */\nexport async function createPrompt(\n client: GraphQLClient,\n options: {\n /** Prompt to create */\n input: {\n /** Title of prompt */\n title: string;\n /** Prompt content */\n content: string;\n };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<string> {\n const { input, logger = NOOP_LOGGER } = options;\n const {\n createPrompt: { prompt },\n } = await makeGraphQLRequest<{\n /** createPrompt mutation */\n createPrompt: {\n /** Prompt */\n prompt: {\n /** ID */\n id: string;\n };\n };\n }>(client, CREATE_PROMPT, {\n // TODO: https://transcend.height.app/T-31994 - include models and groups, teams, users\n variables: { input },\n logger,\n });\n logger.info(`Successfully created prompt \"${input.title}\"!`);\n return prompt.id;\n}\n\n/**\n * Update a set of existing prompts\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updatePrompts(\n client: GraphQLClient,\n options: {\n /** [PromptInput, promptId] list */\n input: [PromptInput, string][];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: prompts, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_PROMPTS, {\n variables: {\n input: {\n prompts: prompts.map(([prompt, id]) => ({\n ...prompt,\n id,\n })),\n },\n },\n logger,\n });\n logger.info(`Successfully updated ${prompts.length} prompts!`);\n}\n\n/**\n * Sync the prompts\n *\n * @param client - GraphQL client\n * @param prompts - Prompts\n * @param options - Options\n * @returns True if synced successfully\n */\nexport async function syncPrompts(\n client: GraphQLClient,\n prompts: PromptInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Concurrency */\n concurrency?: number;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER, concurrency = 20 } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${prompts.length}\" prompts...`);\n\n // Index existing prompts\n const existing = await fetchAllPrompts(client, { logger });\n const promptByTitle = keyBy(existing, 'title');\n\n // Determine which prompts are new vs existing\n const mapPromptsToExisting = prompts.map((promptInput) => [\n promptInput,\n promptByTitle[promptInput.title]?.id,\n ]);\n\n // Create the new prompts\n const newPrompts = mapPromptsToExisting\n .filter(([, existing]) => !existing)\n .map(([promptInput]) => promptInput as PromptInput);\n try {\n logger.info(`Creating \"${newPrompts.length}\" new prompts...`);\n await map(\n newPrompts,\n async (prompt) => {\n await createPrompt(client, { input: prompt, logger });\n },\n {\n concurrency,\n },\n );\n logger.info(`Successfully synced ${newPrompts.length} prompts!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create prompts! - ${(err as Error).message}`);\n }\n\n // Update existing prompts\n const existingPrompts = mapPromptsToExisting.filter((x): x is [PromptInput, string] => !!x[1]);\n try {\n logger.info(`Updating \"${existingPrompts.length}\" prompts...`);\n await updatePrompts(client, { input: existingPrompts, logger });\n logger.info(`Successfully updated \"${existingPrompts.length}\" prompts!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create prompts! - ${(err as Error).message}`);\n }\n\n logger.info(`Synced \"${prompts.length}\" prompts!`);\n\n return !encounteredError;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\n// orderBy: [\n// { field: createdAt, direction: ASC }\n// { field: title, direction: ASC }\n// ]\nexport const GLOBAL_ACTION_ITEM_COLLECTIONS = gql`\n query TranscendCliGlobalActionItemCollectionss(\n $filterBy: GlobalActionItemCollectionFiltersInput!\n ) {\n globalActionItemCollections(filterBy: $filterBy) {\n nodes {\n id\n title\n description\n hidden\n productLine\n }\n }\n }\n`;\n\nexport const CREATE_ACTION_ITEM_COLLECTION = gql`\n mutation TranscendCliCreateActionItemCollection($input: CreateActionItemCollectionInput!) {\n createActionItemCollection(input: $input) {\n created {\n id\n title\n }\n }\n }\n`;\n\nexport const UPDATE_ACTION_ITEM_COLLECTION = gql`\n mutation TranscendCliUpdateActionItemCollection($input: UpdateActionItemCollectionInput!) {\n updateActionItemCollection(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { TranscendProduct } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { GLOBAL_ACTION_ITEM_COLLECTIONS } from './gqls/actionItemCollection.js';\n\nexport interface ActionItemCollection {\n /** ID of collection */\n id: string;\n /** Title of collection */\n title: string;\n /** Description of collection */\n description: string;\n /** Whether section is hidden */\n hidden: boolean;\n /** Which locations/products the action item shows up in */\n productLine: TranscendProduct;\n}\n\n/**\n * Fetch all action item collections in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All action item collections in the organization\n */\nexport async function fetchAllActionItemCollections(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter by */\n filterBy?: {\n /** Filter on location */\n location?: TranscendProduct;\n };\n } = {},\n): Promise<ActionItemCollection[]> {\n const { logger, filterBy = {} } = options;\n const {\n globalActionItemCollections: { nodes },\n } = await makeGraphQLRequest<{\n /** ActionItemCollections */\n globalActionItemCollections: {\n /** List */\n nodes: ActionItemCollection[];\n };\n }>(client, GLOBAL_ACTION_ITEM_COLLECTIONS, {\n variables: {\n filterBy: {\n ...filterBy,\n },\n },\n logger,\n });\n return nodes;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\n// orderBy: [\n// { field: createdAt, direction: ASC }\n// { field: title, direction: ASC }\n// ]\nexport const GLOBAL_ACTION_ITEMS = gql`\n query TranscendCliGlobalActionItems(\n $first: Int!\n $offset: Int!\n $filterBy: GlobalActionItemFiltersInput!\n ) {\n globalActionItems(first: $first, offset: $offset, filterBy: $filterBy) {\n nodes {\n ids\n count\n teams {\n id\n name\n }\n customerExperienceActionItemIds\n users {\n id\n email\n }\n collections {\n title\n id\n }\n dueDate\n priority\n titles\n resolved\n notes\n links\n type\n additionalContexts {\n iconOverride\n requestId\n dataSiloId\n requestType\n latestAirgapVersion\n parentTitle\n }\n attributeValues {\n name\n attributeKey {\n name\n }\n }\n }\n }\n }\n`;\n\nexport const UPDATE_ACTION_ITEMS = gql`\n mutation TranscendCliUpdateActionItems($input: UpdateActionItemsInput!) {\n updateActionItems(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const CREATE_ACTION_ITEMS = gql`\n mutation TranscendCliCreateActionItems($input: [CreateActionItemsInput!]!) {\n createActionItems(input: $input) {\n clientMutationId\n }\n }\n`;\n","import { ActionItemCode, ActionItemPriorityOverride } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { GLOBAL_ACTION_ITEMS } from './gqls/actionItem.js';\n\nexport interface ActionItemRaw {\n /** ID of action item */\n ids: string[];\n /** Count of action items */\n count: number;\n /** Teams assigned to action items */\n teams: {\n /** ID of team */\n id: string;\n /** Name of team */\n name: string;\n }[];\n /** Customer experience action item ID */\n customerExperienceActionItemIds: string[];\n /** Users assigned to the action item */\n users: {\n /** ID of user */\n id: string;\n /** User email */\n email: string;\n }[];\n /** Due date of action item */\n dueDate?: string;\n /** Priority of action item */\n priority?: ActionItemPriorityOverride;\n /** Titles of action items */\n titles: string[];\n /** Description of the action item */\n resolved: boolean;\n /** Notes */\n notes: string[];\n /** links */\n links: string[];\n /** Action item types */\n type: ActionItemCode;\n /** Custom fields */\n attributeValues: {\n /** Name of attribute value */\n name: string;\n /** Attribute key that the value represents */\n attributeKey: {\n /** Name of attribute team */\n name: string;\n };\n }[];\n /** Additional context related to action item */\n additionalContexts?: {\n /** Override of icon */\n iconOverride?: string;\n /** Request ID */\n requestId?: string;\n /** Data Silo ID */\n dataSiloId?: string;\n /** Request type */\n requestType?: string;\n /** Airgap version */\n latestAirgapVersion?: string;\n /** Parent title */\n parentTitle?: string;\n };\n /** Sections where action item is grouped under */\n collections: {\n /** ID of collection that action item belongs to */\n id: string;\n /** Title of collection */\n title: string;\n }[];\n}\n\nexport interface ActionItem extends Omit<ActionItemRaw, 'ids' | 'titles' | 'links' | 'notes'> {\n /** ID of action item */\n id: string;\n /** Title of action item */\n title: string;\n /** Notes */\n notes: string;\n /** Links */\n link: string;\n /** Sections where action item is grouped under */\n collections: {\n /** ID of collection that action item belongs to */\n id: string;\n /** Title of collection */\n title: string;\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all action items in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All action items in the organization\n */\nexport async function fetchAllActionItems(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Filter by */\n filterBy?: {\n /** Names of the action items to filter for */\n priority?: ActionItemPriorityOverride[];\n /** Type of action item */\n type?: ActionItemCode[];\n /** Whether resolved or not */\n resolved?: boolean;\n /** Filter for action items due before this date */\n startDueDate?: Date;\n /** Filter for action items due after this date */\n endDueDate?: Date;\n };\n } = {},\n): Promise<ActionItem[]> {\n const { logger, filterBy = {} } = options;\n const actionItems: ActionItem[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n globalActionItems: { nodes },\n } = await makeGraphQLRequest<{\n /** ActionItems */\n globalActionItems: {\n /** List */\n nodes: ActionItemRaw[];\n };\n }>(client, GLOBAL_ACTION_ITEMS, {\n variables: {\n first: PAGE_SIZE,\n offset,\n filterBy: {\n ...filterBy,\n ...(filterBy.startDueDate ? { startDueDate: filterBy.startDueDate.toISOString() } : {}),\n ...(filterBy.endDueDate ? { endDueDate: filterBy.endDueDate.toISOString() } : {}),\n },\n },\n logger,\n });\n actionItems.push(\n ...nodes.map((node) => ({\n ...node,\n id: node.ids[0]!,\n title: node.titles[0]!,\n notes: node.notes[0]!,\n link: node.links[0]!,\n })),\n );\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return actionItems;\n}\n","import { gql } from 'graphql-request';\n\nexport const ASSESSMENT_SECTION_FIELDS = `\n id\n title\n status\n index\n questions {\n id\n title\n index\n type\n subType\n placeholder\n description\n isRequired\n displayLogic\n riskLogic\n requireRiskEvaluation\n requireRiskMatrixEvaluation\n riskCategories {\n id\n title\n }\n riskFramework {\n id\n title\n description\n riskLevels {\n id\n title\n }\n riskCategories {\n id\n title\n }\n riskMatrixColumns {\n id\n title\n }\n riskMatrixRows {\n id\n title\n }\n riskMatrix {\n id\n title\n }\n creator {\n id\n email\n name\n }\n riskMatrixRowTitle\n riskMatrixColumnTitle\n }\n riskLevel {\n id\n title\n }\n reviewerRiskLevel {\n id\n title\n }\n riskLevelFromRiskMatrix {\n id\n title\n }\n answerOptions {\n id\n index\n value\n }\n selectedAnswers {\n ... on AssessmentAnswerInterface {\n id\n index\n value\n }\n }\n respondent {\n id\n email\n name\n }\n attributeKey {\n name\n }\n externalRespondentEmail\n comments {\n id\n content\n createdAt\n updatedAt\n author {\n id\n email\n name\n }\n }\n allowedMimeTypes\n updatedAt\n referenceId\n previousSubmissions {\n id\n updatedAt\n assessmentQuestionId\n answers {\n ... on AssessmentAnswerInterface {\n id\n index\n value\n }\n }\n }\n allowSelectOther\n syncModel\n syncColumn\n syncRowIds\n syncOverride\n }\n assignees {\n id\n email\n name\n }\n externalAssignees {\n id\n email\n }\n isReviewed\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\n// orderBy: [\n// { field: createdAt, direction: ASC }\n// { field: name, direction: ASC }\n// ]\nexport const ASSESSMENTS = gql`\n query TranscendCliAssessments(\n $first: Int!\n $offset: Int!\n $filterBy: AssessmentFormFiltersInput\n ) {\n assessmentForms(first: $first, offset: $offset, filterBy: $filterBy) {\n nodes {\n id\n creator {\n id\n email\n name\n }\n lastEditor {\n id\n email\n name\n }\n title\n description\n status\n assignees {\n id\n email\n name\n }\n externalAssignees {\n id\n email\n }\n reviewers {\n id\n email\n name\n }\n isLocked\n isArchived\n isExternallyCreated\n dueDate\n createdAt\n updatedAt\n assignedAt\n submittedAt\n approvedAt\n rejectedAt\n titleIsInternal\n retentionSchedule {\n id\n type\n durationDays\n operation\n }\n attributeValues {\n name\n attributeKey {\n name\n }\n }\n sections {\n ${ASSESSMENT_SECTION_FIELDS}\n }\n assessmentGroup {\n id\n title\n description\n }\n resources {\n resourceType\n ... on AttributeBusinessEntityResource {\n id\n title\n }\n ... on AttributeDataSiloResource {\n id\n title\n }\n ... on AttributeDataSubCategoryResource {\n id\n name\n category\n }\n ... on AttributeSubDataPointResource {\n id\n name\n }\n ... on AttributeProcessingPurposeSubCategoryResource {\n id\n name\n purpose\n }\n ... on AttributeRequestResource {\n id\n type\n }\n ... on AttributeVendorResource {\n id\n title\n }\n ... on AttributePromptResource {\n id\n title\n }\n ... on AttributePromptRunResource {\n id\n title\n }\n ... on AttributePromptGroupResource {\n id\n title\n }\n }\n syncedRows {\n resourceType\n ... on AttributeBusinessEntityResource {\n id\n title\n }\n ... on AttributeDataSiloResource {\n id\n title\n }\n ... on AttributeDataSubCategoryResource {\n id\n name\n category\n }\n ... on AttributeSubDataPointResource {\n id\n name\n }\n ... on AttributeProcessingPurposeSubCategoryResource {\n id\n name\n purpose\n }\n ... on AttributeVendorResource {\n id\n title\n }\n }\n }\n }\n }\n`;\n\nexport const IMPORT_ONE_TRUST_ASSESSMENT_FORMS = gql`\n mutation TranscendCliImportOneTrustAssessmentForms($input: ImportOnetrustAssessmentsInput!) {\n importOneTrustAssessmentForms(input: $input) {\n assessmentForms {\n id\n title\n }\n }\n }\n`;\n","import {\n AssessmentFormStatus,\n AssessmentQuestionSubType,\n AssessmentQuestionType,\n AssessmentSyncColumn,\n AssessmentSyncModel,\n AttributeSupportedResourceType,\n DataCategoryType,\n ProcessingPurpose,\n RetentionScheduleOperation,\n RetentionScheduleType,\n} from '@transcend-io/privacy-types';\n/* eslint-disable max-lines */\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { ASSESSMENTS } from './gqls/assessment.js';\n\n/**\n * Represents an assessment with various properties and metadata.\n */\nexport interface Assessment {\n /** The ID of the assessment */\n id: string;\n /** The user who created the assessment */\n creator: UserPreview;\n /** The user who last edited the assessment */\n lastEditor: UserPreview;\n /** The title of the assessment */\n title: string;\n /** The description of the assessment */\n description: string;\n /** The current status of the assessment */\n status: AssessmentFormStatus;\n /** The users assigned to the assessment */\n assignees: UserPreview[];\n /** The external users assigned to the assessment */\n externalAssignees: ExternalUser[];\n /** The users who are reviewers of the assessment */\n reviewers: UserPreview[];\n /** Indicates if the assessment is locked */\n isLocked: boolean;\n /** Indicates if the assessment is archived */\n isArchived: boolean;\n /** Indicates if the assessment was created externally */\n isExternallyCreated: boolean;\n /** The due date of the assessment */\n dueDate: string;\n /** The date when the assessment was created */\n createdAt: string;\n /** The date when the assessment was last updated */\n updatedAt: string;\n /** The date when the assessment was assigned */\n assignedAt: string;\n /** The date when the assessment was submitted */\n submittedAt: string;\n /** The date when the assessment was approved */\n approvedAt: string;\n /** The date when the assessment was rejected */\n rejectedAt: string;\n /** Indicates if the title of the assessment is internal */\n titleIsInternal: boolean;\n /** The retention schedule of the assessment */\n retentionSchedule?: RetentionSchedule;\n /** The attribute values associated with the assessment */\n attributeValues: AttributeValue[];\n /** The sections of the assessment */\n sections: AssessmentSection[];\n /** The group to which the assessment belongs */\n assessmentGroup: AssessmentGroup;\n /** The resources associated with the assessment */\n resources: AssessmentResource[];\n /** The rows that are synced with the assessment */\n syncedRows: AssessmentResource[];\n}\n\nexport interface UserPreview {\n /** ID of user */\n id: string;\n /** Email of user */\n email: string;\n /** Name of user */\n name: string;\n}\n\nexport interface ExternalUser {\n /** ID of external user */\n id: string;\n /** Email of external user */\n email: string;\n}\n\nexport interface RetentionSchedule {\n /** ID of retention schedule */\n id: string;\n /** Type */\n type: RetentionScheduleType;\n /** Duration of retention schedule */\n durationDays: number;\n /** The operation to perform on the retention schedule */\n operation: RetentionScheduleOperation;\n}\n\ninterface AttributeValue {\n /** Name of attribute value */\n name: string;\n /** Key */\n attributeKey: {\n /** Name of key */\n name: string;\n };\n}\n\nexport interface AssessmentSection {\n /** ID of section */\n id: string;\n /** Title of section */\n title: string;\n /** Status of section */\n status: string;\n /** Index of section */\n index: number;\n /** Questions */\n questions: AssessmentQuestion[];\n /** Assignees */\n assignees: UserPreview[];\n /** External assignees */\n externalAssignees: ExternalUser[];\n /** Whether is reviewed */\n isReviewed: boolean;\n}\n\n/**\n * Represents a question in the assessment.\n */\nexport interface AssessmentQuestion {\n /**\n * Unique identifier for the question.\n */\n id: string;\n /** Title of the question */\n title: string;\n /** Index of the question in the assessment */\n index: number;\n /** Type of the question */\n type: AssessmentQuestionType;\n /** Subtype of the question */\n subType: AssessmentQuestionSubType;\n /** Placeholder text for the question */\n placeholder: string;\n /** Description of the question */\n description: string;\n /** Indicates if the question is required */\n isRequired: boolean;\n /** Logic for displaying the question */\n displayLogic: string;\n /** Logic for assessing risk related to the question */\n riskLogic: string[];\n /** Indicates if risk evaluation is required for the question */\n requireRiskEvaluation: boolean;\n /** Indicates if risk matrix evaluation is required for the question */\n requireRiskMatrixEvaluation: boolean;\n /** Categories of risk associated with the question */\n riskCategories: RiskCategory[];\n /** Framework used for risk assessment */\n riskFramework?: RiskFramework;\n /** Level of risk associated with the question */\n riskLevel?: RiskLevel;\n /** Risk level assigned by the reviewer */\n reviewerRiskLevel?: RiskLevel;\n /** Risk level derived from the risk matrix */\n riskLevelFromRiskMatrix?: RiskLevel;\n /** Options available for answering the question */\n answerOptions: AssessmentAnswerOption[];\n /** Answers selected for the question */\n selectedAnswers: AssessmentAnswer[];\n /** User who responded to the question */\n respondent: UserPreview;\n /** Key attribute associated with the question */\n attributeKey?: {\n /** Name of key */\n name: string;\n };\n /** Email of the external respondent */\n externalRespondentEmail?: string;\n /** Comments related to the question */\n comments: unknown[];\n /** Allowed MIME types for file uploads in the question */\n allowedMimeTypes: string[];\n /** Timestamp of the last update to the question */\n updatedAt: string;\n /** Reference identifier for the question */\n referenceId: string;\n /** Previous submissions related to the question */\n previousSubmissions: AssessmentPreviousSubmission[];\n /** Indicates if selecting \"Other\" is allowed for the question */\n allowSelectOther: boolean;\n /** Model used for synchronization */\n syncModel: AssessmentSyncModel;\n /** Column used for synchronization */\n syncColumn: AssessmentSyncColumn;\n /** Row IDs used for synchronization */\n syncRowIds: string[];\n /** Indicates if synchronization override is allowed */\n syncOverride: boolean;\n}\n\nexport interface RiskCategory {\n /** ID of category */\n id: string;\n /** Title of category */\n title: string;\n}\n\nexport interface RiskFramework {\n /** ID of framework */\n id: string;\n /** Title of framework */\n title: string;\n /** Description of framework */\n description: string;\n /** Risk levels */\n riskLevels: RiskLevel[];\n /** Risk categories */\n riskCategories: RiskCategory[];\n /** Risk matrix columns */\n riskMatrixColumns: RiskMatrixColumn[];\n /** Risk matrix rows */\n riskMatrixRows: RiskMatrixRow[];\n /** Risk matrix settings */\n riskMatrix: RiskMatrix[][];\n /** Creator of risk framework */\n creator?: UserPreview;\n /** Risk matrix row title */\n riskMatrixRowTitle: string;\n /** Risk matrix column title */\n riskMatrixColumnTitle: string;\n}\n\nexport interface RiskLevel {\n /** ID of risk level */\n id: string;\n /** Title of risk level */\n title: string;\n}\n\nexport interface RiskMatrix {\n /** ID of risk matrix */\n id: string;\n /** Title of risk matrix */\n title: string;\n}\n\nexport interface RiskMatrixColumn {\n /** ID of column */\n id: string;\n /** Title of column */\n title: string;\n}\n\nexport interface RiskMatrixRow {\n /** ID of row */\n id: string;\n /** Title of row */\n title: string;\n}\n\nexport interface AssessmentAnswerOption {\n /** ID of answer option */\n id: string;\n /** Index of answer option */\n index: number;\n /** Value of answer */\n value: string;\n}\n\nexport interface AssessmentAnswer {\n /** ID of answer */\n id: string;\n /** Index of answer */\n index: number;\n /** Value of answer */\n value: string;\n}\n\nexport interface AssessmentComment {\n /** ID of comment */\n id: string;\n /** Content of comment */\n content: string;\n /** Date comment made */\n createdAt: string;\n /** Date comment updated */\n updatedAt: string;\n /** Author of comment */\n author?: UserPreview;\n}\n\nexport interface AssessmentPreviousSubmission {\n /** Id of submission */\n id: string;\n /** Date updated */\n updatedAt: string;\n /** ID of question */\n assessmentQuestionId: string;\n /** Answers */\n answers: AssessmentAnswer[];\n}\n\nexport interface AssessmentGroup {\n /** ID of group */\n id: string;\n /** Title of group */\n title: string;\n /** Description of group */\n description: string;\n}\n\nexport interface AssessmentResource {\n /** Type of resource */\n resourceType: AttributeSupportedResourceType;\n /** ID of resource */\n id: string;\n /** Title of resource */\n title?: string;\n /** Name of resource */\n name?: string;\n /** Category of resource */\n category?: DataCategoryType;\n /** Purpose of resource */\n purpose?: ProcessingPurpose;\n /** Type of integration */\n type?: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all assessments in the organization\n *\n * @param client - GraphQL client\n * @returns All assessments in the organization\n */\nexport async function fetchAllAssessments(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Assessment[]> {\n const { logger } = options;\n const assessments: Assessment[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n assessmentForms: { nodes },\n } = await makeGraphQLRequest<{\n /** Forms */\n assessmentForms: {\n /** Nodes */\n nodes: Assessment[];\n };\n }>(client, ASSESSMENTS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n assessments.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return assessments.sort((a, b) => a.title.localeCompare(b.title));\n}\n/* eslint-enable max-lines */\n","import {\n AssessmentsDisplayLogicAction,\n ComparisonOperator,\n LogicOperator,\n} from '@transcend-io/privacy-types';\nimport { decodeCodec, valuesOf } from '@transcend-io/type-utils';\nimport * as t from 'io-ts';\n\n// This codec is for rules that logically require a list of values to compare against.\nexport const AssessmentRuleWithOperands = t.type({\n dependsOnQuestionReferenceId: t.string,\n comparisonOperator: t.union([\n t.literal(ComparisonOperator.IsEqualTo),\n t.literal(ComparisonOperator.IsNotEqualTo),\n t.literal(ComparisonOperator.IsOneOf),\n t.literal(ComparisonOperator.IsNotOneOf),\n t.literal(ComparisonOperator.Contains),\n t.literal(ComparisonOperator.DoesNotContain),\n ]),\n comparisonOperands: t.array(t.string),\n});\n\n// This codec is for the specific rule that does NOT require comparison operands.\nexport const AssessmentRuleWithoutOperands = t.type({\n dependsOnQuestionReferenceId: t.string,\n comparisonOperator: t.union([\n t.literal(ComparisonOperator.IsNotShown),\n t.literal(ComparisonOperator.IsShown),\n ]),\n});\n\n/**\n * The final, flexible codec that accepts EITHER a rule with operands OR a rule without them.\n */\nexport const AssessmentRule = t.union([AssessmentRuleWithOperands, AssessmentRuleWithoutOperands]);\n/** Type override */\nexport type AssessmentRule = t.TypeOf<typeof AssessmentRule>;\n\nexport interface AssessmentNestedRule {\n /** The operator to use when comparing the nested rules */\n logicOperator: LogicOperator;\n /** The rules to evaluate and be compared with to other using the LogicOperator */\n rules?: AssessmentRule[];\n /** The nested rules to add one more level of nesting to the rules. They are also compared to each other. */\n nestedRules?: AssessmentNestedRule[];\n}\n\nexport const AssessmentNestedRule: t.RecursiveType<t.Type<AssessmentNestedRule>> = t.recursion(\n 'AssessmentNestedRule',\n (self) =>\n t.intersection([\n t.type({\n /** The operator to use when comparing the nested rules */\n logicOperator: valuesOf(LogicOperator),\n }),\n t.partial({\n /** The rules to evaluate and be compared with to other using the LogicOperator */\n rules: t.array(AssessmentRule),\n /** The nested rules to add one more level of nesting to the rules. They are also compared to each other. */\n nestedRules: t.array(self),\n }),\n ]),\n);\n\nexport const AssessmentAction = t.partial({\n action: valuesOf(AssessmentsDisplayLogicAction),\n rule: AssessmentRule,\n nestedRule: AssessmentNestedRule,\n});\n\n/** Type override */\nexport type AssessmentAction = t.TypeOf<typeof AssessmentAction>;\n\n/**\n * Parse the assessment display logic\n *\n * @param displayLogic - Stringified rule\n * @returns The parsed assessment display logic\n */\nexport function parseAssessmentDisplayLogic(displayLogic: string): AssessmentAction {\n return decodeCodec(AssessmentAction, displayLogic);\n}\n","import { ComparisonOperator } from '@transcend-io/privacy-types';\nimport { decodeCodec, valuesOf } from '@transcend-io/type-utils';\nimport * as t from 'io-ts';\n\nexport const AssessmentRiskLogic = t.intersection([\n t.partial({\n riskAssignment: t.partial({\n riskLevelId: t.string,\n riskMatrixRowId: t.string,\n riskMatrixColumnId: t.string,\n }),\n }),\n t.type({\n comparisonOperands: t.array(t.string),\n comparisonOperator: valuesOf(ComparisonOperator),\n }),\n]);\n\n/** Type override */\nexport type AssessmentRiskLogic = t.TypeOf<typeof AssessmentRiskLogic>;\n\n/**\n * Parse the assessment risk logic\n *\n * @param riskLogic - Stringified rule\n * @returns The parsed assessment risk logic\n */\nexport function parseAssessmentRiskLogic(riskLogic: string): AssessmentRiskLogic {\n return decodeCodec(AssessmentRiskLogic, riskLogic);\n}\n","import { TranscendProduct } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport {\n type ActionItemCollection,\n fetchAllActionItemCollections,\n} from './fetchAllActionItemCollections.js';\nimport {\n CREATE_ACTION_ITEM_COLLECTION,\n UPDATE_ACTION_ITEM_COLLECTION,\n} from './gqls/actionItemCollection.js';\n\nexport interface ActionItemCollectionInput {\n /** The display title of the collection */\n title: string;\n /** Locations where collection is shown */\n productLine: TranscendProduct;\n /** Description of collection */\n description?: string;\n /** Whether hidden */\n hidden?: boolean;\n}\n\n/**\n * Create a new action item collection\n *\n * @param client - GraphQL client\n * @param actionItemCollection - Input\n * @param options - Options\n * @returns Created action item collection\n */\nexport async function createActionItemCollection(\n client: GraphQLClient,\n options: {\n /** Action item collection to create */\n input: ActionItemCollectionInput;\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Pick<ActionItemCollection, 'id' | 'title'>> {\n const { input: actionItemCollection, logger = NOOP_LOGGER } = options;\n const input = {\n title: actionItemCollection.title,\n description: actionItemCollection.description || '',\n hidden: actionItemCollection.hidden || false,\n productLine: actionItemCollection.productLine,\n };\n\n const { createActionItemCollection } = await makeGraphQLRequest<{\n /** Create actionItemCollection mutation */\n createActionItemCollection: {\n /** Created actionItemCollection */\n created: ActionItemCollection;\n };\n }>(client, CREATE_ACTION_ITEM_COLLECTION, {\n variables: { input },\n logger,\n });\n return createActionItemCollection.created;\n}\n\n/**\n * Update an action item collection\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateActionItemCollection(\n client: GraphQLClient,\n options: {\n /** Action item collection input to update */\n input: ActionItemCollectionInput & {\n /** ID of action item collection to update */\n id: string;\n };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<void> {\n const { input: actionItemCollection, logger = NOOP_LOGGER } = options;\n await makeGraphQLRequest(client, UPDATE_ACTION_ITEM_COLLECTION, {\n variables: {\n input: {\n id: actionItemCollection.id,\n title: actionItemCollection.title,\n description: actionItemCollection.description,\n hidden: actionItemCollection.hidden,\n productLine: actionItemCollection.productLine,\n },\n },\n logger,\n });\n}\n\n/**\n * Sync the action item collections\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncActionItemCollections(\n client: GraphQLClient,\n inputs: ActionItemCollectionInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${inputs.length}\" action item collections...`);\n\n const existingActionItemCollections = await fetchAllActionItemCollections(client, { logger });\n\n const collectionByTitle: { [k in string]: ActionItemCollection } = keyBy(\n existingActionItemCollections,\n 'title',\n );\n\n const newCollections = inputs.filter((input) => !collectionByTitle[input.title]);\n\n await mapSeries(newCollections, async (input) => {\n try {\n await createActionItemCollection(client, { input, logger });\n logger.info(`Successfully created action item collection \"${input.title}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to create action item collection \"${input.title}\"! - ${(err as Error).message}`,\n );\n }\n });\n\n const actionItemsToUpdate = inputs\n .map((input) => [input, collectionByTitle[input.title]?.id])\n .filter((x): x is [ActionItemCollectionInput, string] => !!x[1]);\n await mapSeries(actionItemsToUpdate, async ([input, actionItemId]) => {\n try {\n await updateActionItemCollection(client, {\n input: { ...input, id: actionItemId },\n logger,\n });\n logger.info(`Successfully synced action item collection \"${input.title}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(\n `Failed to sync action item collection \"${input.title}\"! - ${(err as Error).message}`,\n );\n }\n });\n\n return !encounteredError;\n}\n","import { ActionItemCode, ActionItemPriorityOverride } from '@transcend-io/privacy-types';\nimport { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { uniq, keyBy, chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport {\n type ActionItemCollection,\n fetchAllActionItemCollections,\n} from './fetchAllActionItemCollections.js';\nimport { fetchAllActionItems, type ActionItem } from './fetchAllActionItems.js';\nimport { UPDATE_ACTION_ITEMS, CREATE_ACTION_ITEMS } from './gqls/actionItem.js';\n\n/** Minimal attribute key shape needed for action item sync */\nexport interface ActionItemAttributeKey {\n /** ID of attribute */\n id: string;\n /** Name of attribute */\n name: string;\n}\n\nexport interface ActionItemInput {\n /** The display title of the action item */\n title: string;\n /** Action item type */\n type: ActionItemCode;\n /** The titles of the collections that the action item is grouped within */\n collections: string[];\n /** Priority of the action item */\n priority?: ActionItemPriorityOverride;\n /** Customer experience action item key */\n customerExperienceActionItemId?: string;\n /** Due date of the action item */\n dueDate?: string;\n /** Whether action item has been resolved */\n resolved?: boolean;\n /** Notes */\n notes?: string;\n /** Links to action items */\n link?: string;\n /** The email addresses of the employees assigned to the action item */\n users?: string[];\n /** The names of teams assigned to the action item */\n teams?: string[];\n /** Attribute value and its corresponding attribute key */\n attributes?: {\n /** Attribute key name */\n key: string;\n /** Attribute value names */\n values: string[];\n }[];\n}\n\n/**\n * Create new action items\n *\n * @param client - GraphQL client\n * @param actionItems - Action item inputs\n * @param actionItemCollectionByTitle - Action item collections indexed by title\n * @param options - Options\n */\nexport async function createActionItems(\n client: GraphQLClient,\n options: {\n /** Action items to create */\n input: ActionItemInput[];\n /** Logger instance */\n logger?: Logger;\n /** Action item collections indexed by title */\n actionItemCollectionByTitle: {\n [k in string]: ActionItemCollection;\n };\n // TODO: https://transcend.height.app/T-38961 - insert attributes\n /** Attribute keys indexed by name */\n attributeKeysByName?: {\n [k in string]: ActionItemAttributeKey;\n };\n },\n): Promise<void> {\n const { input: actionItems, logger = NOOP_LOGGER, actionItemCollectionByTitle } = options;\n // TODO: https://transcend.height.app/T-38961 - insert attributes\n // const getAttribute = (key: string): string => {\n // const existing = attributeKeysByName[key];\n // if (!existing) {\n // throw new Error(`Attribute key \"${key}\" does not exist!`);\n // }\n // return existing.id;\n // };\n const chunked = chunk(actionItems, 100);\n await mapSeries(chunked, async (chunkToUpload) => {\n await makeGraphQLRequest(client, CREATE_ACTION_ITEMS, {\n variables: {\n input: chunkToUpload.map((actionItem) => ({\n title: actionItem.title,\n type: actionItem.type,\n priorityOverride: actionItem.priority,\n dueDate: actionItem.dueDate,\n customerExperienceActionItemId: actionItem.customerExperienceActionItemId,\n resolved: actionItem.resolved,\n notes: actionItem.notes,\n link: actionItem.link,\n assigneesUserEmails: actionItem.users,\n assigneesTeamNames: actionItem.teams,\n ...(actionItem.attributes\n ? {\n // TODO: https://transcend.height.app/T-38961 - insert attributes\n // attributes: actionItem.attributes.map(({ key, values }) => ({\n // attributeKeyId: getAttribute(key),\n // attributeValueNames: values,\n // })),\n }\n : {}),\n collectionIds: actionItem.collections.map(\n (collectionTitle) => actionItemCollectionByTitle[collectionTitle]!.id,\n ),\n })),\n },\n logger,\n });\n });\n}\n\n/**\n * Update an action item\n *\n * @param client - GraphQL client\n * @param options - Options\n */\nexport async function updateActionItem(\n client: GraphQLClient,\n options: {\n /** Action item input to update */\n input: ActionItemInput & {\n /** ID of action item to update */\n id: string;\n };\n /** Logger instance */\n logger?: Logger;\n /** Attribute keys indexed by name */\n attributeKeysByName?: {\n [k in string]: ActionItemAttributeKey;\n };\n },\n): Promise<void> {\n const { input: actionItem, logger = NOOP_LOGGER, attributeKeysByName = {} } = options;\n const getAttribute = (key: string): string => {\n const existing = attributeKeysByName[key];\n if (!existing) {\n throw new Error(`Attribute key \"${key}\" does not exist!`);\n }\n return existing.id;\n };\n await makeGraphQLRequest(client, UPDATE_ACTION_ITEMS, {\n variables: {\n input: {\n ids: [actionItem.id],\n title: actionItem.title,\n priorityOverride: actionItem.priority,\n dueDate: actionItem.dueDate,\n resolved: actionItem.resolved,\n customerExperienceActionItemId: actionItem.customerExperienceActionItemId,\n notes: actionItem.notes,\n link: actionItem.link,\n assigneesUserEmails: actionItem.users,\n assigneesTeamNames: actionItem.teams,\n ...(actionItem.attributes\n ? {\n attributes: actionItem.attributes.map(({ key, values }) => ({\n attributeKeyId: getAttribute(key),\n attributeValueNames: values,\n })),\n }\n : {}),\n },\n },\n logger,\n });\n}\n\n/**\n * Convert action item to a unique key\n *\n * @param actionItem - action item\n * @returns Unique key\n */\nfunction actionItemToUniqueCode({\n title,\n collections,\n}: Pick<ActionItem, 'title' | 'collections'>): string {\n return `${title}-${collections\n .map((c) => c.title)\n .sort()\n .join('-')}`;\n}\n\n/**\n * Convert action item input to a unique key\n *\n * @param actionItem - action item\n * @returns Unique key\n */\nfunction actionItemInputToUniqueCode({\n title,\n collections,\n}: Pick<ActionItemInput, 'title' | 'collections'>): string {\n return `${title}-${collections.sort().join('-')}`;\n}\n\n/**\n * Sync the action items\n *\n * @param client - GraphQL client\n * @param inputs - Inputs to create\n * @param options - Options\n * @returns True if run without error, returns false if an error occurred\n */\nexport async function syncActionItems(\n client: GraphQLClient,\n inputs: ActionItemInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Pre-fetched attribute keys (pass result of fetchAllAttributes) */\n attributeKeys?: ActionItemAttributeKey[];\n } = {},\n): Promise<boolean> {\n const { logger = NOOP_LOGGER, attributeKeys = [] } = options;\n let encounteredError = false;\n logger.info(`Syncing \"${inputs.length}\" actionItems...`);\n\n const [existingActionItems, existingActionItemCollections] = await Promise.all([\n fetchAllActionItems(client, { logger }),\n fetchAllActionItemCollections(client, { logger }),\n ]);\n\n const actionItemCollectionByTitle: { [k in string]: ActionItemCollection } = keyBy(\n existingActionItemCollections,\n 'title',\n );\n const actionItemByTitle = keyBy(existingActionItems, actionItemToUniqueCode) as {\n [k in string]: ActionItem;\n };\n const attributeKeysByName = keyBy(attributeKeys, 'name');\n const actionItemByCxId = keyBy(\n existingActionItems.filter((x) => !!x.customerExperienceActionItemIds),\n ({ customerExperienceActionItemIds }) => customerExperienceActionItemIds[0],\n ) as { [k in string]: ActionItem };\n\n const missingCollections = uniq(inputs.map((input) => input.collections).flat()).filter(\n (collectionTitle) => !actionItemCollectionByTitle[collectionTitle],\n );\n if (missingCollections.length > 0) {\n logger.error(\n `Missing action item collections: \"${missingCollections.join(\n '\", \"',\n )}\" - please create them first!`,\n );\n return false;\n }\n\n const newActionItems = inputs.filter(\n (input) =>\n !actionItemByTitle[actionItemInputToUniqueCode(input)] &&\n !actionItemByCxId[input.customerExperienceActionItemId!],\n );\n\n if (newActionItems.length > 0) {\n try {\n logger.info(`Creating \"${newActionItems.length}\" actionItems...`);\n await createActionItems(client, {\n input: newActionItems,\n logger,\n actionItemCollectionByTitle,\n attributeKeysByName,\n });\n logger.info(`Successfully created \"${newActionItems.length}\" actionItems!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create action items! - ${(err as Error).message}`);\n }\n }\n\n const actionItemsToUpdate = inputs\n .map((input) => [\n input,\n actionItemByTitle[actionItemInputToUniqueCode(input)]?.id ||\n actionItemByCxId[input.customerExperienceActionItemId!]?.id,\n ])\n .filter((x): x is [ActionItemInput, string] => !!x[1]);\n await mapSeries(actionItemsToUpdate, async ([input, actionItemId]) => {\n try {\n await updateActionItem(client, {\n input: { ...input, id: actionItemId },\n logger,\n attributeKeysByName,\n });\n logger.info(`Successfully synced action item \"${input.title}\"!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to sync action item \"${input.title}\"! - ${(err as Error).message}`);\n }\n });\n\n return !encounteredError;\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const CODE_PACKAGES = gql`\n query TranscendCliCodePackages($first: Int!, $offset: Int!, $input: CodePackageFiltersInput) {\n codePackages(\n first: $first\n offset: $offset\n filterBy: $input\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n description\n type\n relativePath\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n repository {\n id\n name\n }\n dataSilo {\n id\n title\n type\n }\n }\n }\n }\n`;\n\nexport const UPDATE_CODE_PACKAGES = gql`\n mutation TranscendCliUpdateCodePackages($input: UpdateCodePackagesInput!) {\n updateCodePackages(input: $input) {\n clientMutationId\n codePackages {\n id\n name\n description\n type\n relativePath\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n repository {\n id\n name\n }\n dataSilo {\n id\n title\n type\n }\n }\n }\n }\n`;\n\nexport const CREATE_CODE_PACKAGE = gql`\n mutation TranscendCliCreateCodePackage($input: CreateCodePackageInput!) {\n createCodePackage(input: $input) {\n clientMutationId\n codePackage {\n id\n name\n description\n type\n relativePath\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n repository {\n id\n name\n }\n dataSilo {\n id\n title\n type\n }\n }\n }\n }\n`;\n","import { CodePackageType } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { CODE_PACKAGES } from './gqls/codePackage.js';\n\nexport interface CodePackage {\n /** ID of code package */\n id: string;\n /** Name of code package */\n name: string;\n /** Description of code package */\n description: string;\n /** Type of code package */\n type: CodePackageType;\n /** Relative path to code package in repository */\n relativePath: string;\n /** The teams that manage the code package */\n teams: {\n /** ID of team */\n id: string;\n /** Name of team */\n name: string;\n }[];\n /** The users that manage the code package */\n owners: {\n /** ID of user */\n id: string;\n /** Email of user */\n email: string;\n }[];\n /** The repository where the code package belongs */\n repository: {\n /** ID of repository */\n id: string;\n /** Name of repository */\n name: string;\n };\n /** The data silo that the code package relates to */\n dataSilo?: {\n /** ID of repository */\n id: string;\n /** Title of repository */\n title: string;\n /** Type of data silo */\n type: string;\n };\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all code packages in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All code packages in the organization\n */\nexport async function fetchAllCodePackages(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<CodePackage[]> {\n const { logger } = options;\n const codePackages: CodePackage[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n codePackages: { nodes },\n } = await makeGraphQLRequest<{\n /** Code packages */\n codePackages: {\n /** List */\n nodes: CodePackage[];\n };\n }>(client, CODE_PACKAGES, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n codePackages.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return codePackages.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const REPOSITORIES = gql`\n query TranscendCliRepositories($first: Int!, $offset: Int!, $input: RepositoryFiltersInput) {\n repositories(\n first: $first\n offset: $offset\n filterBy: $input\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n description\n url\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n }\n }\n }\n`;\n\nexport const UPDATE_REPOSITORIES = gql`\n mutation TranscendCliUpdateRepositories($input: UpdateRepositoriesInput!) {\n updateRepositories(input: $input) {\n clientMutationId\n repositories {\n id\n name\n url\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n }\n }\n }\n`;\n\nexport const CREATE_REPOSITORY = gql`\n mutation TranscendCliCreateRepository($input: CreateRepositoryInput!) {\n createRepository(input: $input) {\n clientMutationId\n repository {\n id\n name\n url\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n }\n }\n }\n`;\n","import type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { REPOSITORIES } from './gqls/repository.js';\n\nexport interface Repository {\n /** ID of repository */\n id: string;\n /** Name of repository */\n name: string;\n /** Description of repository */\n description: string;\n /** URL of repo */\n url: string;\n /** The teams that manage the repository */\n teams: {\n /** ID of team */\n id: string;\n /** Name of team */\n name: string;\n }[];\n /** The users that manage the repository */\n owners: {\n /** ID of user */\n id: string;\n /** Email of user */\n email: string;\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all repositories in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All repositories in the organization\n */\nexport async function fetchAllRepositories(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<Repository[]> {\n const { logger } = options;\n const repositories: Repository[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n repositories: { nodes },\n } = await makeGraphQLRequest<{\n /** Repositories */\n repositories: {\n /** List */\n nodes: Repository[];\n };\n }>(client, REPOSITORIES, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n repositories.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return repositories.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { gql } from 'graphql-request';\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\n// useMaster: false\nexport const SOFTWARE_DEVELOPMENT_KITS = gql`\n query TranscendCliSoftwareDevelopmentKits(\n $first: Int!\n $offset: Int!\n $input: SoftwareDevelopmentKitFiltersInput\n ) {\n softwareDevelopmentKits(\n first: $first\n offset: $offset\n filterBy: $input\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n description\n codePackageType\n documentationLinks\n repositoryUrl\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n }\n }\n }\n`;\n\nexport const UPDATE_SOFTWARE_DEVELOPMENT_KITS = gql`\n mutation TranscendCliUpdateSoftwareDevelopmentKits($input: UpdateSoftwareDevelopmentKitsInput!) {\n updateSoftwareDevelopmentKits(input: $input) {\n clientMutationId\n softwareDevelopmentKits {\n id\n name\n description\n codePackageType\n documentationLinks\n repositoryUrl\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n }\n }\n }\n`;\n\nexport const CREATE_SOFTWARE_DEVELOPMENT_KIT = gql`\n mutation TranscendCliCreateSoftwareDevelopmentKit($input: CreateSoftwareDevelopmentKitInput!) {\n createSoftwareDevelopmentKit(input: $input) {\n clientMutationId\n softwareDevelopmentKit {\n id\n name\n description\n codePackageType\n documentationLinks\n repositoryUrl\n teams {\n id\n name\n }\n owners {\n id\n email\n }\n }\n }\n }\n`;\n","import { CodePackageType } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { SOFTWARE_DEVELOPMENT_KITS } from './gqls/softwareDevelopmentKit.js';\n\nexport interface SoftwareDevelopmentKit {\n /** ID of software development kit */\n id: string;\n /** Name of software development kit */\n name: string;\n /** Description of software development kit */\n description: string;\n /** Type of software development kit */\n codePackageType: CodePackageType;\n /** Related documentation */\n documentationLinks: string[];\n /** Link to git repository */\n repositoryUrl?: string;\n /** The teams that manage the software development kit */\n teams: {\n /** ID of team */\n id: string;\n /** Name of team */\n name: string;\n }[];\n /** The users that manage the software development kit */\n owners: {\n /** ID of user */\n id: string;\n /** Email of user */\n email: string;\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all software development kits in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All software development kits in the organization\n */\nexport async function fetchAllSoftwareDevelopmentKits(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger?: Logger;\n } = {},\n): Promise<SoftwareDevelopmentKit[]> {\n const { logger } = options;\n const softwareDevelopmentKits: SoftwareDevelopmentKit[] = [];\n let offset = 0;\n\n // Whether to continue looping\n let shouldContinue = false;\n do {\n const {\n softwareDevelopmentKits: { nodes },\n } = await makeGraphQLRequest<{\n /** Software development kits */\n softwareDevelopmentKits: {\n /** List */\n nodes: SoftwareDevelopmentKit[];\n };\n }>(client, SOFTWARE_DEVELOPMENT_KITS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\n });\n softwareDevelopmentKits.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return softwareDevelopmentKits.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { mapSeries, map, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk, keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport { fetchAllRepositories, type Repository } from './fetchAllRepositories.js';\nimport { UPDATE_REPOSITORIES, CREATE_REPOSITORY } from './gqls/repository.js';\n\nexport interface RepositoryInput {\n /** Title of repository */\n name: string;\n /** Description of the repository */\n description?: string;\n /** Github repository URL */\n url: string;\n}\n\nconst CHUNK_SIZE = 100;\n\n/**\n * Create a new repository\n *\n * @param client - GraphQL client\n * @param input - Repository input\n * @param options - Options\n * @returns Created repository\n */\nexport async function createRepository(\n client: GraphQLClient,\n options: {\n /** Repository to create */\n input: {\n /** Title of repository */\n name: string;\n /** Description of the repository */\n description?: string;\n /** Github repository */\n url: string;\n /** User IDs of owners */\n ownerIds?: string[];\n /** Emails of owners */\n ownerEmails?: string[];\n /** Team IDs */\n teamIds?: string[];\n /** Team names */\n teamNames?: string[];\n };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Repository> {\n const { input, logger = NOOP_LOGGER } = options;\n const {\n createRepository: { repository },\n } = await makeGraphQLRequest<{\n /** createRepository mutation */\n createRepository: {\n /** Software development kit */\n repository: Repository;\n };\n }>(client, CREATE_REPOSITORY, {\n variables: { input },\n logger,\n });\n logger.info(`Successfully created repository \"${input.name}\"!`);\n return repository;\n}\n\n/**\n * Update an existing repository\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Updated repositories\n */\nexport async function updateRepositories(\n client: GraphQLClient,\n options: {\n /** Repository inputs to update */\n input: {\n /** ID of repository */\n id: string;\n /** Title of repository */\n name?: string;\n /** Description of the repository */\n description?: string;\n /** Github repository */\n url?: string;\n /** User IDs of owners */\n ownerIds?: string[];\n /** Emails of owners */\n ownerEmails?: string[];\n /** Team IDs */\n teamIds?: string[];\n /** Team names */\n teamNames?: string[];\n }[];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<Repository[]> {\n const { input: repositories, logger = NOOP_LOGGER } = options;\n const {\n updateRepositories: { repositories: updatedRepositories },\n } = await makeGraphQLRequest<{\n /** updateRepositories mutation */\n updateRepositories: {\n /** Software development kit */\n repositories: Repository[];\n };\n }>(client, UPDATE_REPOSITORIES, {\n variables: {\n input: {\n repositories,\n },\n },\n logger,\n });\n logger.info(`Successfully updated ${repositories.length} repositories!`);\n return updatedRepositories;\n}\n\n/**\n * Sync the repositories\n *\n * @param client - GraphQL client\n * @param repositories - Repositories\n * @param options - Options\n * @returns The repositories that were upserted and whether the sync was successful\n */\nexport async function syncRepositories(\n client: GraphQLClient,\n repositories: RepositoryInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Concurrency */\n concurrency?: number;\n } = {},\n): Promise<{\n /** The repositories that were upserted */\n repositories: Repository[];\n /** If successful */\n success: boolean;\n}> {\n const { logger = NOOP_LOGGER, concurrency = 20 } = options;\n let encounteredError = false;\n const repos: Repository[] = [];\n\n // Index existing repositories\n const existing = await fetchAllRepositories(client, { logger });\n const repositoryByName = keyBy(existing, 'name');\n\n // Determine which repositories are new vs existing\n const mapRepositoriesToExisting = repositories.map((repoInput) => [\n repoInput,\n repositoryByName[repoInput.name]?.id,\n ]);\n\n // Create the new repositories\n const newRepositories = mapRepositoriesToExisting\n .filter(([, existing]) => !existing)\n .map(([repoInput]) => repoInput as RepositoryInput);\n try {\n logger.info(`Creating \"${newRepositories.length}\" new repositories...`);\n await map(\n newRepositories,\n async (repo) => {\n const newRepo = await createRepository(client, { input: repo, logger });\n repos.push(newRepo);\n },\n {\n concurrency,\n },\n );\n logger.info(`Successfully synced ${newRepositories.length} repositories!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create repositories! - ${(err as Error).message}`);\n }\n\n // Update existing repositories\n const existingRepositories = mapRepositoriesToExisting.filter(\n (x): x is [RepositoryInput, string] => !!x[1],\n );\n const chunks = chunk(existingRepositories, CHUNK_SIZE);\n logger.info(`Updating \"${existingRepositories.length}\" repositories...`);\n\n await mapSeries(chunks, async (chunk) => {\n try {\n const updatedRepos = await updateRepositories(client, {\n input: chunk.map(([input, id]) => ({\n ...input,\n id,\n })),\n logger,\n });\n repos.push(...updatedRepos);\n logger.info(`Successfully updated \"${existingRepositories.length}\" repositories!`);\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to update repositories! - ${(err as Error).message}`);\n }\n\n logger.info(`Synced \"${repositories.length}\" repositories!`);\n });\n\n // Return true upon success\n return {\n repositories: repos,\n success: !encounteredError,\n };\n}\n","import { CodePackageType } from '@transcend-io/privacy-types';\nimport { mapSeries, map, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk, keyBy } from 'lodash-es';\n\nimport { makeGraphQLRequest, NOOP_LOGGER } from '../api/makeGraphQLRequest.js';\nimport {\n fetchAllSoftwareDevelopmentKits,\n type SoftwareDevelopmentKit,\n} from './fetchAllSoftwareDevelopmentKits.js';\nimport {\n UPDATE_SOFTWARE_DEVELOPMENT_KITS,\n CREATE_SOFTWARE_DEVELOPMENT_KIT,\n} from './gqls/softwareDevelopmentKit.js';\n\nexport interface SoftwareDevelopmentKitInput {\n /** Title of software development kit */\n name: string;\n /** Code package type */\n codePackageType: CodePackageType;\n /** Description of the SDK */\n description?: string;\n /** Github repository URL */\n repositoryUrl?: string;\n /** Integration name */\n catalogIntegrationName?: string;\n /** Documentation links */\n documentationLinks?: string[];\n}\n\nconst CHUNK_SIZE = 100;\n\n/**\n * Create a new software development kit\n *\n * @param client - GraphQL client\n * @param input - Software development kit input\n * @param options - Options\n * @returns Created software development kit\n */\nexport async function createSoftwareDevelopmentKit(\n client: GraphQLClient,\n options: {\n /** Software development kit to create */\n input: {\n /** Title of software development kit */\n name: string;\n /** Code package type */\n codePackageType: CodePackageType;\n /** Description of the SDK */\n description?: string;\n /** Github repository */\n repositoryUrl?: string;\n /** Integration name */\n catalogIntegrationName?: string;\n /** Doc links */\n documentationLinks?: string[];\n /** Code package IDs */\n codePackageIds?: string[];\n /** Code package names */\n codePackageNames?: string[];\n /** User IDs of owners */\n ownerIds?: string[];\n /** Emails of owners */\n ownerEmails?: string[];\n /** Team IDs */\n teamIds?: string[];\n /** Team names */\n teamNames?: string[];\n };\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<SoftwareDevelopmentKit> {\n const { input, logger = NOOP_LOGGER } = options;\n const {\n createSoftwareDevelopmentKit: { softwareDevelopmentKit },\n } = await makeGraphQLRequest<{\n /** createSoftwareDevelopmentKit mutation */\n createSoftwareDevelopmentKit: {\n /** Software development kit */\n softwareDevelopmentKit: SoftwareDevelopmentKit;\n };\n }>(client, CREATE_SOFTWARE_DEVELOPMENT_KIT, {\n variables: { input },\n logger,\n });\n logger.info(`Successfully created software development kit \"${input.name}\"!`);\n return softwareDevelopmentKit;\n}\n\n/**\n * Update an existing software development kit\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns Updated software development kits\n */\nexport async function updateSoftwareDevelopmentKits(\n client: GraphQLClient,\n options: {\n /** Software development kit inputs to update */\n input: {\n /** ID of software development kit */\n id: string;\n /** Title of software development kit */\n name?: string;\n /** Description of the SDK */\n description?: string;\n /** Github repository */\n repositoryUrl?: string;\n /** Integration name */\n catalogIntegrationName?: string;\n /** Doc links */\n documentationLinks?: string[];\n /** Code package IDs */\n codePackageIds?: string[];\n /** Code package names */\n codePackageNames?: string[];\n /** User IDs of owners */\n ownerIds?: string[];\n /** Emails of owners */\n ownerEmails?: string[];\n /** Team IDs */\n teamIds?: string[];\n /** Team names */\n teamNames?: string[];\n }[];\n /** Logger instance */\n logger?: Logger;\n },\n): Promise<SoftwareDevelopmentKit[]> {\n const { input: sdks, logger = NOOP_LOGGER } = options;\n const {\n updateSoftwareDevelopmentKits: { softwareDevelopmentKits },\n } = await makeGraphQLRequest<{\n /** updateSoftwareDevelopmentKits mutation */\n updateSoftwareDevelopmentKits: {\n /** Software development kit */\n softwareDevelopmentKits: SoftwareDevelopmentKit[];\n };\n }>(client, UPDATE_SOFTWARE_DEVELOPMENT_KITS, {\n variables: {\n input: {\n softwareDevelopmentKits: sdks,\n },\n },\n logger,\n });\n logger.info(`Successfully updated ${sdks.length} software development kits!`);\n return softwareDevelopmentKits;\n}\n\n/**\n * Sync the software development kits\n *\n * @param client - GraphQL client\n * @param softwareDevelopmentKits - Software development kits\n * @param options - Options\n * @returns The software development kits that were upserted and whether the sync was successful\n */\nexport async function syncSoftwareDevelopmentKits(\n client: GraphQLClient,\n softwareDevelopmentKits: SoftwareDevelopmentKitInput[],\n options: {\n /** Logger instance */\n logger?: Logger;\n /** Concurrency */\n concurrency?: number;\n } = {},\n): Promise<{\n /** The SDKs that were upserted */\n softwareDevelopmentKits: SoftwareDevelopmentKit[];\n /** If successful */\n success: boolean;\n}> {\n const { logger = NOOP_LOGGER, concurrency = 20 } = options;\n let encounteredError = false;\n const sdks: SoftwareDevelopmentKit[] = [];\n logger.info('Syncing software development kits...');\n\n // Index existing software development kits\n const existing = await fetchAllSoftwareDevelopmentKits(client, { logger });\n const softwareDevelopmentKitByTitle = keyBy(existing, ({ name, codePackageType }) =>\n JSON.stringify({ name, codePackageType }),\n );\n\n // Determine which software development kits are new vs existing\n const mapSoftwareDevelopmentKitsToExisting = softwareDevelopmentKits.map((sdkInput) => [\n sdkInput,\n softwareDevelopmentKitByTitle[\n JSON.stringify({\n name: sdkInput.name,\n codePackageType: sdkInput.codePackageType,\n })\n ]?.id,\n ]);\n\n // Create the new software development kits\n const newSoftwareDevelopmentKits = mapSoftwareDevelopmentKitsToExisting\n .filter(([, existing]) => !existing)\n .map(([sdkInput]) => sdkInput as SoftwareDevelopmentKitInput);\n try {\n logger.info(`Creating \"${newSoftwareDevelopmentKits.length}\" new software development kits...`);\n await map(\n newSoftwareDevelopmentKits,\n async (sdk) => {\n const newSdk = await createSoftwareDevelopmentKit(client, { input: sdk, logger });\n sdks.push(newSdk);\n },\n {\n concurrency,\n },\n );\n logger.info(\n `Successfully synced ${newSoftwareDevelopmentKits.length} software development kits!`,\n );\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to create software development kits! - ${(err as Error).message}`);\n }\n\n // Update existing software development kits\n const existingSoftwareDevelopmentKits = mapSoftwareDevelopmentKitsToExisting.filter(\n (x): x is [SoftwareDevelopmentKitInput, string] => !!x[1],\n );\n const chunks = chunk(existingSoftwareDevelopmentKits, CHUNK_SIZE);\n logger.info(`Updating \"${existingSoftwareDevelopmentKits.length}\" software development kits...`);\n\n await mapSeries(chunks, async (chunk) => {\n try {\n const updatedSdks = await updateSoftwareDevelopmentKits(client, {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n input: chunk.map(([{ codePackageType, ...input }, id]) => ({\n ...input,\n id,\n })),\n logger,\n });\n sdks.push(...updatedSdks);\n logger.info(\n `Successfully updated \"${existingSoftwareDevelopmentKits.length}\" software development kits!`,\n );\n } catch (err) {\n encounteredError = true;\n logger.error(`Failed to update software development kits! - ${(err as Error).message}`);\n }\n\n logger.info(`Synced \"${softwareDevelopmentKits.length}\" software development kits!`);\n });\n\n // Return true upon success\n return {\n softwareDevelopmentKits: sdks,\n success: !encounteredError,\n };\n}\n","import { describePackageName } from '@transcend-io/utils';\n\nexport interface MonorepoPackageDefinition {\n directory: string;\n displayName: string;\n packageName: string;\n}\n\nexport function createMonorepoPackageDefinition(\n name: string,\n directory: string,\n): MonorepoPackageDefinition {\n const packageNameParts = describePackageName(name);\n\n return {\n directory,\n displayName: packageNameParts.displayName,\n packageName: `@transcend-io/${packageNameParts.slug}`,\n };\n}\n\nexport * from './gqls/index.js';\nexport * from './api/index.js';\nexport * from './data-inventory/index.js';\nexport * from './preference-management/index.js';\nexport * from './administration/index.js';\nexport * from './consent/index.js';\nexport * from './dsr-automation/index.js';\nexport * from './ai/index.js';\nexport * from './assessments/index.js';\nexport * from './code-intelligence/index.js';\n"],"mappings":"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"}
|