@transcend-io/sdk 0.0.0 → 0.1.0
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/LICENSE +201 -0
- package/dist/index.d.mts +42925 -12
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +6594 -130
- package/dist/index.mjs.map +1 -1
- package/package.json +30 -17
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["PAGE_SIZE","PAGE_SIZE"],"sources":["../src/api/buildTranscendGraphQLClient.ts","../src/api/makeGraphQLRequest.ts","../src/api/gqls/organization.ts","../src/api/createSombraGotInstance.ts","../src/data-inventory/gqls/identifier.ts","../src/data-inventory/fetchAllIdentifiers.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/index.ts"],"sourcesContent":["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\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 { variables, logger, requestHeaders, maxRetries = DEFAULT_MAX_RETRIES } = 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 } 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, 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.extend({\n prefixUrl: sombraToUse,\n headers: {\n Authorization: `Bearer ${transcendApiKey}`,\n ...(sombraApiKey ? { 'X-Sombra-Authorization': `Bearer ${sombraApiKey}` } : {}),\n },\n });\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: { /** type of data subjects */ type: string }[];\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: { /** Default message */ defaultMessage: string };\n /** Display description for identifier */\n displayDescription: { /** Default */ defaultMessage: string };\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: { /** Logger instance */ logger: Logger },\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: { /** List */ nodes: Identifier[] };\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 { 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 /** Whether to include deleted purposes */\n includeDeleted?: boolean;\n },\n): Promise<Purpose[]> {\n const { logger, 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: { /** List */ nodes: Purpose[] };\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: { /** ID */ id: string; /** Default message */ defaultMessage: string };\n /** Whether to show in privacy center */\n showInPrivacyCenter: boolean;\n /** Description to display in privacy center */\n displayDescription: { /** ID */ id: string; /** Default message */ defaultMessage: string };\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: { /** ID */ id: string; /** Default message */ defaultMessage: string };\n }[];\n /** Related purpose */\n purpose: { /** Slug */ trackingType: string };\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: { /** List */ nodes: PreferenceTopic[] };\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: { /** Logger instance */ logger: Logger },\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: { /** Token */ token: string }[];\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 { 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 './api/index.js';\nexport * from './data-inventory/index.js';\nexport * from './preference-management/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","PAGE_SIZE","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","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE","CHUNK_SIZE","CHUNK_SIZE","PAGE_SIZE","PAGE_SIZE","PAGE_SIZE"],"sources":["../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/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/syncBusinessEntities.ts","../src/data-inventory/syncDataCategories.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/fetchConsentManagerId.ts","../src/consent/fetchAllCookies.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/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/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/dsr-automation/gqls/siloDiscovery.ts","../src/dsr-automation/fetchActiveSiloDiscoPlugin.ts","../src/dsr-automation/gqls/action.ts","../src/dsr-automation/fetchAllActions.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/syncAction.ts","../src/dsr-automation/gqls/template.ts","../src/dsr-automation/syncTemplates.ts","../src/dsr-automation/uploadSiloDiscoveryResults.ts","../src/index.ts"],"sourcesContent":["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\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 { variables, logger, requestHeaders, maxRetries = DEFAULT_MAX_RETRIES } = 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 } 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, 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.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 { 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 { 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 } from '../api/makeGraphQLRequest.js';\nimport { fetchAllBusinessEntities, 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 businessEntity: BusinessEntityInput,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<BusinessEntity> {\n const { 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 businessEntityIdParis - [BusinessEntityInput, businessEntityId] list\n */\nexport async function updateBusinessEntities(\n client: GraphQLClient,\n businessEntityIdParis: [BusinessEntityInput, string][],\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { logger } = options;\n const chunkedUpdates = chunk(businessEntityIdParis, 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 } = 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, businessEntity, { logger });\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(\n client,\n 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 } from '../api/makeGraphQLRequest.js';\nimport { fetchAllDataCategories, 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 dataCategory: DataCategoryInput,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<Pick<DataSubCategory, 'id' | 'name' | 'category'>> {\n const { 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 dataCategoryIdPairs - [DataCategoryInput, dataCategoryId] list\n * @param options - Options\n */\nexport async function updateDataCategories(\n client: GraphQLClient,\n dataCategoryIdPairs: [DataCategoryInput, string][],\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { logger } = options;\n await makeGraphQLRequest(client, UPDATE_DATA_SUB_CATEGORIES, {\n variables: {\n input: {\n dataSubCategories: dataCategoryIdPairs.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 } = 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, 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(\n client,\n inputs.map((input) => [input, dataCategoryByName[`${input.name}:${input.category}`]!.id]),\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 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 } from '../api/makeGraphQLRequest.js';\nimport {\n fetchAllProcessingActivities,\n 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 } = 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 } = 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 } = 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 } from '../api/makeGraphQLRequest.js';\nimport { fetchAllVendors, 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 vendor: VendorInput,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<Pick<Vendor, 'id' | 'title'>> {\n const { 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 vendorIdParis - [VendorInput, vendorId] list\n */\nexport async function updateVendors(\n client: GraphQLClient,\n vendorIdParis: [VendorInput, string][],\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { logger } = options;\n await makeGraphQLRequest(client, UPDATE_VENDORS, {\n variables: {\n input: {\n vendors: vendorIdParis.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 } = 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, 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(\n client,\n 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 /** Whether to include deleted purposes */\n includeDeleted?: boolean;\n },\n): Promise<Purpose[]> {\n const { logger, 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\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,\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, 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 { ConsentPreferenceResponse, PreferencesQueryFilter, 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,\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 { getComparisonTimeForRecord } from './getComparisonTimeForRecord.js';\nimport { iterateConsentPages } from './iterateConsentPages.js';\nimport { pickConsentChunkMode } from './pickConsentChunkMode.js';\nimport { ChunkMode, 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 } = 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 } = 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 { ConsentPreferenceResponse, 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,\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 { 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,\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 { 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 { PreferencesQueryFilter, 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,\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 attributeKeyId: string,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<AttributeValue[]> {\n const { logger } = 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, node.id, { logger })\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 } 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 /** Filter on titles */\n titles?: string[];\n /** Logger instance */\n logger: Logger;\n },\n): Promise<ApiKey[]> {\n const { titles, logger } = 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 apiKeyInputs - API keys to fetch metadata on\n * @param client - GraphQL client\n * @param fetchAll - When true, fetch all API keys\n * @param options - Options\n * @returns A map from apiKey title to Identifier\n */\nexport async function fetchApiKeys(\n { 'api-keys': apiKeyInputs = [], 'data-silos': dataSilos = [] }: FetchApiKeysInput,\n client: GraphQLClient,\n fetchAll = false,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<{ [k in string]: ApiKey }> {\n const { logger } = options;\n logger.info(`Fetching ${fetchAll ? 'all' : apiKeyInputs.length} API keys...`);\n const titles = apiKeyInputs.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 titles: fetchAll ? undefined : [...expectedApiKeyTitles, ...titles],\n logger,\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 - Email/password\n * @returns Cookie and roles\n */\nexport async function loginUser(\n client: GraphQLClient,\n {\n email,\n password,\n logger,\n }: {\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 {\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 - Email/password\n */\nexport async function assumeRole(\n client: GraphQLClient,\n {\n email,\n roleId,\n logger,\n }: {\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 {\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 input - Input\n * @param options - Options\n * @returns The API key\n */\nexport async function createApiKey(\n client: GraphQLClient,\n input: {\n /** Title of API key */\n title: string;\n /** Scopes for API key */\n scopes: ScopeName[];\n },\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<CreatedApiKey> {\n const { logger } = 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 }, logger });\n\n return apiKey;\n}\n\n/**\n * Delete an API key\n *\n * @param client - GraphQL client\n * @param id - API key Id\n * @param options - Options\n */\nexport async function deleteApiKey(\n client: GraphQLClient,\n id: string,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { 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 } from '../api/makeGraphQLRequest.js';\nimport { 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,\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 } 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 messageInputs - List of message inputs\n */\nexport async function updateIntlMessages(\n client: GraphQLClient,\n messageInputs: IntlMessageInput[],\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { logger } = options;\n // Batch update messages\n await mapSeries(chunk(messageInputs, 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 } = 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, 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 } from '../api/makeGraphQLRequest.js';\nimport { fetchAllTeams, 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 team: TeamInput,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<Pick<Team, 'id' | 'name'>> {\n const { 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 input - Team input to update\n * @param teamId - ID of team\n * @param options - Options\n * @returns Updated team\n */\nexport async function updateTeam(\n client: GraphQLClient,\n input: TeamInput,\n teamId: string,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<Pick<Team, 'id' | 'name'>> {\n const { logger } = options;\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: input.name,\n description: input.description,\n ssoTitle: input['sso-title'],\n ssoDepartment: input['sso-department'],\n ssoGroup: input['sso-group'],\n scopes: input.scopes,\n userEmails: input.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 } = 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, 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, input, teamsByName[input.name]!.id, { logger });\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, { 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.extend({\n prefixUrl: transcendUrl,\n });\n}\n","/* eslint-disable max-lines */\nimport { 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 EXPERIENCES = gql`\n query TranscendCliExperiences($first: Int!, $offset: Int!) {\n experiences(first: $first, offset: $offset, useMaster: false) {\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// 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\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\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 {\n id\n }\n }\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// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const DATA_FLOWS = gql`\n query TranscendCliDataFlows(\n $first: Int!\n $airgapBundleId: ID!\n $offset: Int!\n $status: ConsentTrackerStatus\n $showZeroActivity: Boolean\n ) {\n dataFlows(\n first: $first\n offset: $offset\n filterBy: { status: $status, showZeroActivity: $showZeroActivity }\n input: { airgapBundleId: $airgapBundleId }\n orderBy: [{ field: createdAt, direction: ASC }, { field: value, direction: ASC }]\n useMaster: false\n ) {\n nodes {\n id\n value\n type\n description\n trackingType\n service {\n integrationName\n }\n source\n status\n owners {\n email\n }\n teams {\n name\n }\n attributeValues {\n name\n attributeKey {\n name\n }\n }\n }\n }\n }\n`;\n\n// TODO: https://transcend.height.app/T-27909 - enable optimizations\n// isExportCsv: true\nexport const COOKIES = gql`\n query TranscendCliCookies(\n $first: Int!\n $offset: Int!\n $airgapBundleId: ID!\n $status: ConsentTrackerStatus\n ) {\n cookies(\n first: $first\n offset: $offset\n filterBy: { status: $status }\n input: { airgapBundleId: $airgapBundleId }\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n useMaster: false\n ) {\n nodes {\n id\n name\n isRegex\n description\n trackingPurposes\n service {\n integrationName\n }\n source\n status\n owners {\n email\n }\n teams {\n name\n }\n attributeValues {\n name\n attributeKey {\n name\n }\n }\n }\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\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\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\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\nexport const UPDATE_CONSENT_EXPERIENCE = gql`\n mutation TranscendCliUpdateConsentExperience($input: UpdateExperienceInput!) {\n updateExperience(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const CREATE_CONSENT_EXPERIENCE = gql`\n mutation TranscendCliCreateConsentExperience($input: CreateExperienceInput!) {\n createExperience(input: $input) {\n clientMutationId\n }\n }\n`;\n\nexport const CREATE_CONSENT_PARTITION = gql`\n mutation TranscendCliCreateConsentPartition($input: CreateConsentPartitionInput!) {\n createConsentPartition(input: $input) {\n clientMutationId\n }\n }\n`;\n/* eslint-enable max-lines */\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 input - Update input\n * @param options - Options\n */\nexport async function updateConsentManagerToLatest(\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, UPDATE_CONSENT_MANAGER_TO_LATEST, {\n variables: { airgapBundleId: input.id, bundleType: input.bundleType },\n logger: options.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 { 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 EXPERIENCES,\n FETCH_CONSENT_MANAGER_THEME,\n} from './gqls/consentManager.js';\nimport { CONSENT_MANAGER_ANALYTICS_DATA } from './gqls/consentManagerMetrics.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\nexport interface ConsentManagerTheme {\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/**\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 airgapBundleId: string,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<ConsentManagerTheme> {\n const {\n consentManagerTheme: { theme },\n } = await makeGraphQLRequest<{\n /** Consent manager query */\n consentManagerTheme: {\n /** Consent manager object */\n theme: ConsentManagerTheme;\n };\n }>(client, FETCH_CONSENT_MANAGER_THEME, {\n variables: { airgapBundleId },\n logger: options.logger,\n });\n return theme;\n}\n","import { ConsentTrackerSource, ConsentTrackerStatus } 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 { COOKIES } from './gqls/consentManager.js';\n\nexport interface Cookie {\n /** ID of the cookie */\n id: string;\n /** Name of the cookie */\n name: string;\n /** Whether cookie is a regular expression */\n isRegex: boolean;\n /** Description of cookie */\n description: string;\n /** Enabled tracking purposes for the cookie */\n trackingPurposes: string[];\n /** The consent service */\n service: {\n /** Integration name of service */\n integrationName: string;\n };\n /** Source of how tracker was added */\n source: ConsentTrackerSource;\n /** Status of cookie labeling */\n status: ConsentTrackerStatus;\n /** Owners of that cookie */\n owners: {\n /** Email address of owner */\n email: string;\n }[];\n /** Teams assigned to that cookie */\n teams: {\n /** Name of team */\n name: string;\n }[];\n /** Attributes assigned to that cookie */\n attributeValues: {\n /** Name of attribute value */\n name: string;\n /** Attribute key that the value represents */\n attributeKey: {\n /** Name of attribute key */\n name: string;\n };\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all Cookies in the organization\n *\n * @param client - GraphQL client\n * @param status - The status to fetch\n * @param options - Options\n * @returns All Cookies in the organization\n */\nexport async function fetchAllCookies(\n client: GraphQLClient,\n status = ConsentTrackerStatus.Live,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<Cookie[]> {\n const { logger } = options;\n const cookies: Cookie[] = [];\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<{\n /** Query response */\n cookies: {\n /** List of matches */\n nodes: Cookie[];\n };\n }>(client, COOKIES, {\n variables: { first: PAGE_SIZE, offset, airgapBundleId, status },\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 {\n DataFlowScope,\n ConsentTrackerSource,\n ConsentTrackerStatus,\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 { fetchConsentManagerId } from './fetchConsentManagerId.js';\nimport { DATA_FLOWS } from './gqls/consentManager.js';\n\nexport interface DataFlow {\n /** ID of data flow */\n id: string;\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 /** Enabled tracking purposes */\n trackingType: string[];\n /** The consent service */\n service: {\n /** Integration name of service */\n integrationName: string;\n };\n /** Source of how tracker was added */\n source: ConsentTrackerSource;\n /** Status of data flow labeling */\n status: ConsentTrackerStatus;\n /** Owners of that data flow */\n owners: {\n /** Email address of owner */\n email: string;\n }[];\n /** Teams assigned to that data flow */\n teams: {\n /** Name of team */\n name: string;\n }[];\n /** Attributes assigned to that data flow */\n attributeValues: {\n /** Name of attribute value */\n name: string;\n /** Attribute key that the value represents */\n attributeKey: {\n /** Name of attribute key */\n name: string;\n };\n }[];\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all DataFlows in the organization\n *\n * @param client - GraphQL client\n * @param status - The status to fetch\n * @param options - Options\n * @returns All DataFlows in the organization\n */\nexport async function fetchAllDataFlows(\n client: GraphQLClient,\n status = ConsentTrackerStatus.Live,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<DataFlow[]> {\n const { logger } = options;\n const dataFlows: DataFlow[] = [];\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<{\n /** Query response */\n dataFlows: {\n /** List of matches */\n nodes: DataFlow[];\n };\n }>(client, DATA_FLOWS, {\n variables: {\n first: PAGE_SIZE,\n offset,\n airgapBundleId,\n status,\n ...(status === ConsentTrackerStatus.NeedsReview ? { showZeroActivity: true } : {}),\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 /** URL to look up */\n url?: string;\n },\n): Promise<string> {\n const { logger } = options;\n let urlToUse = options.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 { mapSeries, type Logger } from '@transcend-io/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { difference } from 'lodash-es';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { fetchConsentManagerId } from './fetchConsentManagerId.js';\nimport { CONSENT_PARTITIONS, CREATE_CONSENT_PARTITION } from './gqls/consentManager.js';\n\nconst PAGE_SIZE = 50;\n\nexport interface TranscendPartition {\n /** ID of the partition */\n id: string;\n /** Name of partition */\n name: string;\n /** Partition value */\n partition: string;\n}\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<TranscendPartition[]> {\n const { logger } = options;\n const partitions: TranscendPartition[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n consentPartitions: { nodes },\n } = await makeGraphQLRequest<{\n /** Consent partitions */\n consentPartitions: {\n /** List */\n nodes: TranscendPartition[];\n };\n }>(client, CONSENT_PARTITIONS, {\n variables: { first: PAGE_SIZE, offset },\n logger,\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 } = 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 } from '../api/makeGraphQLRequest.js';\nimport { fetchAllPurposes } from '../preference-management/fetchAllPurposes.js';\nimport { fetchConsentManagerId, fetchConsentManagerExperiences } from './fetchConsentManagerId.js';\nimport { fetchPrivacyCenterId, fetchPrivacyCenterUrl } 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_EXPERIENCE,\n CREATE_CONSENT_EXPERIENCE,\n UPDATE_CONSENT_MANAGER_THEME,\n} from './gqls/consentManager.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 } = 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 } = 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 } from '../api/makeGraphQLRequest.js';\nimport { fetchConsentManagerId } from './fetchConsentManagerId.js';\nimport { UPDATE_OR_CREATE_COOKIES } from './gqls/consentManager.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 cookieInputs - List of cookie inputs\n * @param options - Options\n */\nexport async function updateOrCreateCookies(\n client: GraphQLClient,\n cookieInputs: CookieInput[],\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { logger } = options;\n const airgapBundleId = await fetchConsentManagerId(client, { logger });\n\n await mapSeries(chunk(cookieInputs, 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 } = 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, 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 } from '../api/makeGraphQLRequest.js';\nimport { fetchAllDataFlows } from './fetchAllDataFlows.js';\nimport { fetchConsentManagerId } from './fetchConsentManagerId.js';\nimport { CREATE_DATA_FLOWS, UPDATE_DATA_FLOWS } from './gqls/consentManager.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 dataFlowInputs - [DataFlowInput, Data Flow ID] mappings to update\n * @param classifyService - Classify service if missing\n * @param options - Options\n */\nexport async function updateDataFlows(\n client: GraphQLClient,\n dataFlowInputs: [DataFlowInput, string][],\n classifyService = false,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { 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, 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 classifyService - Classify service if missing\n * @param options - Options\n */\nexport async function createDataFlows(\n client: GraphQLClient,\n dataFlowInputs: DataFlowInput[],\n classifyService = false,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { 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 classifyService - When true, auto classify the service based on the data flow value\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 classifyService: boolean,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<boolean> {\n const { 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, ConsentTrackerStatus.Live, { logger }),\n fetchAllDataFlows(client, ConsentTrackerStatus.NeedsReview, { logger }),\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, 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, 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 } 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 policyInputs - List of policy input\n * @param options - Options\n */\nexport async function updatePolicies(\n client: GraphQLClient,\n policyInputs: [PolicyInput, string | undefined][],\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { 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 } = 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(\n client,\n 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 } 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 } = 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 } from '../api/makeGraphQLRequest.js';\nimport {\n fetchAllProcessingPurposes,\n 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 processingPurpose: ProcessingPurposeInput,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<Pick<ProcessingPurposeSubCategory, 'id' | 'name' | 'purpose'>> {\n const input = {\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 },\n logger: options.logger,\n });\n return createProcessingPurposeSubCategory.processingPurposeSubCategory;\n}\n\n/**\n * Input to update processing purposes\n *\n * @param client - GraphQL client\n * @param processingPurposeIdPairs - [ProcessingPurposeInput, processingPurposeId] list\n * @param options - Options\n */\nexport async function updateProcessingPurposes(\n client: GraphQLClient,\n processingPurposeIdPairs: [ProcessingPurposeInput, string][],\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n await makeGraphQLRequest(client, UPDATE_PROCESSING_PURPOSE_SUB_CATEGORIES, {\n variables: {\n input: {\n processingPurposeSubCategories: processingPurposeIdPairs.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: options.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 } = 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, 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(\n client,\n inputs.map((input) => [input, processingPurposeByName[`${input.name}:${input.purpose}`]!.id]),\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\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 by prompt titles */\n promptTitles?: string[];\n /** Filter by prompt ids */\n promptIds?: string[];\n },\n): Promise<TranscendPromptsAndVariables> {\n const { logger, promptTitles = [], 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 } from '../api/makeGraphQLRequest.js';\nimport { fetchAllAgentFiles, 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 agentFile: AgentFileInput,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<Pick<AgentFile, 'id' | 'name' | 'fileId'>> {\n const { 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 agentFileIdPairs - [AgentFileInput, agentFileId] list\n * @param options - Options\n */\nexport async function updateAgentFiles(\n client: GraphQLClient,\n agentFileIdPairs: [AgentFileInput, string][],\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { logger } = options;\n await makeGraphQLRequest(client, UPDATE_AGENT_FILES, {\n variables: {\n input: {\n agentFiles: agentFileIdPairs.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 } = 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, 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(\n client,\n 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 } from '../api/makeGraphQLRequest.js';\nimport { fetchAllAgentFunctions, 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 agentFunction: AgentFunctionInput,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<Pick<AgentFunction, 'id' | 'name'>> {\n const { 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 agentFunctionIdPairs - [AgentFunctionInput, agentFunctionId] list\n * @param options - Options\n */\nexport async function updateAgentFunctions(\n client: GraphQLClient,\n agentFunctionIdPairs: [AgentFunctionInput, string][],\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { logger } = options;\n await makeGraphQLRequest(client, UPDATE_AGENT_FUNCTIONS, {\n variables: {\n input: {\n agentFunctions: agentFunctionIdPairs.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 } = 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, 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(\n client,\n 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 } from '../api/makeGraphQLRequest.js';\nimport { fetchAllAgents, 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 agent: AgentInput,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<Pick<Agent, 'id' | 'name' | 'agentId'>> {\n const { 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 agentIdPairs - [AgentInput, agentId] list\n * @param options - Options\n */\nexport async function updateAgents(\n client: GraphQLClient,\n agentIdPairs: [AgentInput, string][],\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { logger } = options;\n await makeGraphQLRequest(client, UPDATE_AGENTS, {\n variables: {\n input: {\n agents: agentIdPairs.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 } = 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, 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(\n client,\n 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 } 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 input: EditPromptGroupInput,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<string> {\n const { 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 input - Prompt input\n * @param options - Options\n */\nexport async function updatePromptGroups(\n client: GraphQLClient,\n input: [EditPromptGroupInput, string][],\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { logger } = options;\n await makeGraphQLRequest(client, UPDATE_PROMPT_GROUPS, {\n variables: {\n input: {\n promptGroups: input.map(([input, id]) => ({\n ...input,\n id,\n })),\n },\n },\n logger,\n });\n logger.info(`Successfully updated ${input.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, 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(\n client,\n {\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(\n client,\n 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 } 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 input: {\n /** Title of prompt partial */\n title: string;\n /** Prompt content */\n content: string;\n },\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<string> {\n const { 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 input - Prompt input\n * @param options - Options\n */\nexport async function updatePromptPartials(\n client: GraphQLClient,\n input: [PromptPartialInput, string][],\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { logger } = options;\n await makeGraphQLRequest(client, UPDATE_PROMPT_PARTIALS, {\n variables: {\n input: {\n promptPartials: input.map(([input, id]) => ({\n ...input,\n id,\n })),\n },\n },\n logger,\n });\n logger.info(`Successfully updated ${input.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, 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, 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, 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 } 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 input: {\n /** Title of prompt */\n title: string;\n /** Prompt content */\n content: string;\n },\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<string> {\n const { 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 input - Prompt input\n * @param options - Options\n */\nexport async function updatePrompts(\n client: GraphQLClient,\n input: [PromptInput, string][],\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { logger } = options;\n await makeGraphQLRequest(client, UPDATE_PROMPTS, {\n variables: {\n input: {\n prompts: input.map(([input, id]) => ({\n ...input,\n id,\n })),\n },\n },\n logger,\n });\n logger.info(`Successfully updated ${input.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, 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, 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, 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 } from '../api/makeGraphQLRequest.js';\nimport {\n 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 actionItemCollection: ActionItemCollectionInput,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<Pick<ActionItemCollection, 'id' | 'title'>> {\n const { 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 input - Input to update\n * @param actionItemCollectionId - ID of action item collection to update\n * @param options - Options\n */\nexport async function updateActionItemCollection(\n client: GraphQLClient,\n input: ActionItemCollectionInput,\n actionItemCollectionId: string,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { logger } = options;\n await makeGraphQLRequest(client, UPDATE_ACTION_ITEM_COLLECTION, {\n variables: {\n input: {\n id: actionItemCollectionId,\n title: input.title,\n description: input.description,\n hidden: input.hidden,\n productLine: input.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 } = 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, input, actionItemId, { logger });\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 } from '../api/makeGraphQLRequest.js';\nimport {\n ActionItemCollection,\n fetchAllActionItemCollections,\n} from './fetchAllActionItemCollections.js';\nimport { fetchAllActionItems, 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 actionItems: ActionItemInput[],\n actionItemCollectionByTitle: {\n [k in string]: ActionItemCollection;\n },\n options: {\n /** Logger instance */\n logger: Logger;\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 { logger } = 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 input - Input to update\n * @param actionItemId - ID of action item to update\n * @param options - Options\n */\nexport async function updateActionItem(\n client: GraphQLClient,\n input: ActionItemInput,\n actionItemId: string,\n options: {\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 { 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: [actionItemId],\n title: input.title,\n priorityOverride: input.priority,\n dueDate: input.dueDate,\n resolved: input.resolved,\n customerExperienceActionItemId: input.customerExperienceActionItemId,\n notes: input.notes,\n link: input.link,\n assigneesUserEmails: input.users,\n assigneesTeamNames: input.teams,\n ...(input.attributes\n ? {\n attributes: input.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, 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, newActionItems, actionItemCollectionByTitle, {\n logger,\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, input, actionItemId, { logger, attributeKeysByName });\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 } from '../api/makeGraphQLRequest.js';\nimport { fetchAllRepositories, 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 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 options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<Repository> {\n const { 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 inputs - Repository input\n * @param options - Options\n * @returns Updated repositories\n */\nexport async function updateRepositories(\n client: GraphQLClient,\n inputs: {\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 options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<Repository[]> {\n const { logger } = options;\n const {\n updateRepositories: { repositories },\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: inputs,\n },\n },\n logger,\n });\n logger.info(`Successfully updated ${inputs.length} repositories!`);\n return repositories;\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, 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, 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(\n client,\n 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 } from '../api/makeGraphQLRequest.js';\nimport {\n fetchAllSoftwareDevelopmentKits,\n 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 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 options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<SoftwareDevelopmentKit> {\n const { 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 inputs - Software development kit input\n * @param options - Options\n * @returns Updated software development kits\n */\nexport async function updateSoftwareDevelopmentKits(\n client: GraphQLClient,\n inputs: {\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 options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<SoftwareDevelopmentKit[]> {\n const { 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: inputs,\n },\n },\n logger,\n });\n logger.info(`Successfully updated ${inputs.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, 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, 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(\n client,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n 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 { 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 } 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 dataSiloId - The data silo to look up plugins for\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 dataSiloId: string,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<Plugin> {\n const { logger } = 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 { 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 { 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 /** Filter by title */\n title?: string;\n /** Logger instance */\n logger: Logger;\n },\n): Promise<Template[]> {\n const { title, logger } = 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, { title: template.title, logger });\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 } 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 pluginId - pluginID to associate with the results\n * @param results - The results\n * @param options - Options\n */\nexport async function uploadSiloDiscoveryResults(\n client: GraphQLClient,\n pluginId: string,\n results: SiloDiscoveryRawResult[],\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<void> {\n const { 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 { 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 './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 './ai/index.js';\nexport * from './assessments/index.js';\nexport * from './code-intelligence/index.js';\nexport * from './consent/index.js';\nexport * from './dsr-automation/index.js';\n"],"mappings":"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"}
|