diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index dae4a85e..a6f024ff 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -1,4 +1,4 @@ -version: "3.8" +version: '3.8' services: app: @@ -17,11 +17,11 @@ services: # Overrides default command so things don't shut down after the process ends. command: /bin/bash -c "sleep infinity" - network_mode: "host" + network_mode: 'host' environment: # This is set to `true` locally when using devcontainers, so we add this here for compatibility - REMOTE_CONTAINERS: "true" + REMOTE_CONTAINERS: 'true' volumes: pre-commit-cache: diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 6bbe05c8..00000000 --- a/.eslintignore +++ /dev/null @@ -1,14 +0,0 @@ -.gitignore -.git/* -**/docs/* -**/package.json -**/node_modules/* -**/build/* -**/dist/* -**/builds/* -**/coverage/* -*.testjs -*.testts -examples/code-scanning/test-package-json/src/* -LICENSE -working/* \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a3ef8ee9..ba816468 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,13 @@ ## Table of Contents - [Changelog](#changelog) - - [[7.0.0] - 2025-07-10](#700---2025-07-10) - - [Improvements](#improvements) - - [Breaking Changes](#breaking-changes) - - [[6.0.0] - 2024-09-03](#600---2024-09-03) - - [Changed](#changed) - - [[5.0.0] - 2024-04-23](#500---2024-04-23) - - [Changed](#changed-1) + - [[7.0.0] - 2025-07-10](#700---2025-07-10) + - [Improvements](#improvements) + - [Breaking Changes](#breaking-changes) + - [[6.0.0] - 2024-09-03](#600---2024-09-03) + - [Changed](#changed) + - [[5.0.0] - 2024-04-23](#500---2024-04-23) + - [Changed](#changed-1) @@ -29,22 +29,22 @@ The CLI has been overhauled to be easier to use as a full-featured command line - All commands have `--help` flag to print help information. For example: - ```console - $ transcend consent update-consent-manager --help + ```console + $ transcend consent update-consent-manager --help - USAGE - transcend consent update-consent-manager (--auth value) (--bundleTypes PRODUCTION|TEST) [--deploy] [--transcendUrl value] - transcend consent update-consent-manager --help + USAGE + transcend consent update-consent-manager (--auth value) (--bundleTypes PRODUCTION|TEST) [--deploy] [--transcendUrl value] + transcend consent update-consent-manager --help - This command allows for updating Consent Manager to latest version. The consent manager bundle can also be deployed using this command. + This command allows for updating Consent Manager to latest version. The consent manager bundle can also be deployed using this command. - FLAGS - --auth The Transcend API key. Requires scopes: "Manage Consent Manager Developer Settings" - --bundleTypes The bundle types to deploy. Defaults to PRODUCTION,TEST. [PRODUCTION|TEST, separator = ,] - [--deploy] When true, deploy the Consent Manager after updating the version [default = false] - [--transcendUrl] URL of the Transcend backend. Use https://api.us.transcend.io for US hosting [default = https://api.transcend.io] - -h --help Print help information and exit - ``` + FLAGS + --auth The Transcend API key. Requires scopes: "Manage Consent Manager Developer Settings" + --bundleTypes The bundle types to deploy. Defaults to PRODUCTION,TEST. [PRODUCTION|TEST, separator = ,] + [--deploy] When true, deploy the Consent Manager after updating the version [default = false] + [--transcendUrl] URL of the Transcend backend. Use https://api.us.transcend.io for US hosting [default = https://api.transcend.io] + -h --help Print help information and exit + ``` - Boolean arguments no longer need to have `=true` or `=false` strings explicitly passed to them. For example, rather than pass `--deploy=true`, you can now pass `--deploy` alone. Passing `--deploy=true` or `--deploy=false` is still supported, as well as other boolean values described [here](https://github.com/bloomberg/stricli/blob/58a10349b427d9e5e7d75bf1767898d095e8544c/packages/core/src/parameter/parser/boolean.ts#L21-L26). For booleans which default to true, you can also prefix `no` to the argument name. For example, `--noDeploy` is equivalent to `--deploy=false`. - List arguments can either be passed as a comma-separated string or as several arguments. For example, `--bundleTypes=PRODUCTION,TEST` is equivalent to `--bundleTypes PRODUCTION --bundleTypes TEST`. @@ -154,50 +154,47 @@ partitions: ... ### Changed - Added support for encrypted identifiers to `tr-manual-enricher-pull-identifiers` command. + - Now that this command is using Sombra to decrypt request identifiers, you may need to provide the `--sombraAuth` argument. It's required when using self-hosted Sombra, but not for multi-tenant. - - Now that this command is using Sombra to decrypt request identifiers, you may need to provide the `--sombraAuth` argument. It's required when using self-hosted Sombra, but not for multi-tenant. + ``` + Before: + yarn tr-manual-enricher-pull-identifiers --auth=$TRANSCEND_API_KEY \ + --actions=ERASURE \ + --file=/Users/michaelfarrell/Desktop/test.csv - ``` - Before: - yarn tr-manual-enricher-pull-identifiers --auth=$TRANSCEND_API_KEY \ - --actions=ERASURE \ - --file=/Users/michaelfarrell/Desktop/test.csv - - Now: - yarn tr-manual-enricher-pull-identifiers --auth=$TRANSCEND_API_KEY \ - --sombraAuth=$SOMBRA_INTERNAL_KEY \ - --actions=ERASURE \ - --file=/Users/michaelfarrell/Desktop/test.csv - ``` + Now: + yarn tr-manual-enricher-pull-identifiers --auth=$TRANSCEND_API_KEY \ + --sombraAuth=$SOMBRA_INTERNAL_KEY \ + --actions=ERASURE \ + --file=/Users/michaelfarrell/Desktop/test.csv + ``` - Added support for encrypted identifiers to `tr-request-export` command. + - Now that this command is using Sombra to decrypt request identifiers, you may need to provide the `--sombraAuth` argument. It's required when using self-hosted Sombra, but not for multi-tenant. - - Now that this command is using Sombra to decrypt request identifiers, you may need to provide the `--sombraAuth` argument. It's required when using self-hosted Sombra, but not for multi-tenant. - - ``` - Before: - yarn tr-request-export --auth=$TRANSCEND_API_KEY \ - --actions=ERASURE \ - --file=/Users/michaelfarrell/Desktop/test.csv + ``` + Before: + yarn tr-request-export --auth=$TRANSCEND_API_KEY \ + --actions=ERASURE \ + --file=/Users/michaelfarrell/Desktop/test.csv - Now: - yarn tr-request-export --auth=$TRANSCEND_API_KEY \ - --sombraAuth=$SOMBRA_INTERNAL_KEY \ - --actions=ERASURE \ - --file=/Users/michaelfarrell/Desktop/test.csv - ``` + Now: + yarn tr-request-export --auth=$TRANSCEND_API_KEY \ + --sombraAuth=$SOMBRA_INTERNAL_KEY \ + --actions=ERASURE \ + --file=/Users/michaelfarrell/Desktop/test.csv + ``` - Added support for encrypted identifiers to `tr-request-restart` command, used only when `--copyIdentifiers` argument is specified. - - - Now that this command is using Sombra to decrypt request identifiers, you may need to provide the `--sombraAuth` argument. It's required only when using `--copyIdentifiers` AND self-hosted Sombra, but is otherwise not required. - - ``` - Before: - yarn tr-request-restart --auth=$TRANSCEND_API_KEY \ - --statuses=COMPILING,APPROVING --actions=ERASURE --copyIdentifiers=true - - Now: - yarn tr-request-restart --auth=$TRANSCEND_API_KEY \ - --sombraAuth=$SOMBRA_INTERNAL_KEY \ - --statuses=COMPILING,APPROVING --actions=ERASURE --copyIdentifiers=true - ``` + - Now that this command is using Sombra to decrypt request identifiers, you may need to provide the `--sombraAuth` argument. It's required only when using `--copyIdentifiers` AND self-hosted Sombra, but is otherwise not required. + + ``` + Before: + yarn tr-request-restart --auth=$TRANSCEND_API_KEY \ + --statuses=COMPILING,APPROVING --actions=ERASURE --copyIdentifiers=true + + Now: + yarn tr-request-restart --auth=$TRANSCEND_API_KEY \ + --sombraAuth=$SOMBRA_INTERNAL_KEY \ + --statuses=COMPILING,APPROVING --actions=ERASURE --copyIdentifiers=true + ``` diff --git a/DEVELOPERS.md b/DEVELOPERS.md index fc498c5b..f7cf15c1 100644 --- a/DEVELOPERS.md +++ b/DEVELOPERS.md @@ -4,13 +4,13 @@ ## Table of Contents - [Developers](#developers) - - [Getting started](#getting-started) - - [Repo Structure](#repo-structure) - - [Generated files](#generated-files) - - [README.md](#readmemd) - - [transcend.yml and pathfinder.yml JSON schemas](#transcendyml-and-pathfinderyml-json-schemas) - - [Testing](#testing) - - [Publishing](#publishing) + - [Getting started](#getting-started) + - [Repo Structure](#repo-structure) + - [Generated files](#generated-files) + - [README.md](#readmemd) + - [transcend.yml and pathfinder.yml JSON schemas](#transcendyml-and-pathfinderyml-json-schemas) + - [Testing](#testing) + - [Publishing](#publishing) diff --git a/README.md b/README.md index 98e7cd4e..30de3733 100644 --- a/README.md +++ b/README.md @@ -10,52 +10,52 @@ - [Installation](#installation) - [transcend.yml](#transcendyml) - [Usage](#usage) - - [`transcend request approve`](#transcend-request-approve) - - [`transcend request upload`](#transcend-request-upload) - - [`transcend request download-files`](#transcend-request-download-files) - - [`transcend request cancel`](#transcend-request-cancel) - - [`transcend request restart`](#transcend-request-restart) - - [`transcend request notify-additional-time`](#transcend-request-notify-additional-time) - - [`transcend request mark-silent`](#transcend-request-mark-silent) - - [`transcend request enricher-restart`](#transcend-request-enricher-restart) - - [`transcend request reject-unverified-identifiers`](#transcend-request-reject-unverified-identifiers) - - [`transcend request export`](#transcend-request-export) - - [`transcend request skip-preflight-jobs`](#transcend-request-skip-preflight-jobs) - - [`transcend request system mark-request-data-silos-completed`](#transcend-request-system-mark-request-data-silos-completed) - - [`transcend request system retry-request-data-silos`](#transcend-request-system-retry-request-data-silos) - - [`transcend request system skip-request-data-silos`](#transcend-request-system-skip-request-data-silos) - - [`transcend request preflight pull-identifiers`](#transcend-request-preflight-pull-identifiers) - - [`transcend request preflight push-identifiers`](#transcend-request-preflight-push-identifiers) - - [`transcend request cron pull-identifiers`](#transcend-request-cron-pull-identifiers) - - [`transcend request cron mark-identifiers-completed`](#transcend-request-cron-mark-identifiers-completed) - - [`transcend consent build-xdi-sync-endpoint`](#transcend-consent-build-xdi-sync-endpoint) - - [`transcend consent pull-consent-metrics`](#transcend-consent-pull-consent-metrics) - - [`transcend consent pull-consent-preferences`](#transcend-consent-pull-consent-preferences) - - [`transcend consent update-consent-manager`](#transcend-consent-update-consent-manager) - - [`transcend consent upload-consent-preferences`](#transcend-consent-upload-consent-preferences) - - [`transcend consent upload-cookies-from-csv`](#transcend-consent-upload-cookies-from-csv) - - [`transcend consent upload-data-flows-from-csv`](#transcend-consent-upload-data-flows-from-csv) - - [`transcend consent upload-preferences`](#transcend-consent-upload-preferences) - - [`transcend inventory pull`](#transcend-inventory-pull) - - [Scopes](#scopes) - - [Usage](#usage-1) - - [`transcend inventory push`](#transcend-inventory-push) - - [Scopes](#scopes-1) - - [Usage](#usage-2) - - [CI Integration](#ci-integration) - - [Dynamic Variables](#dynamic-variables) - - [`transcend inventory scan-packages`](#transcend-inventory-scan-packages) - - [`transcend inventory discover-silos`](#transcend-inventory-discover-silos) - - [Usage](#usage-3) - - [`transcend inventory pull-datapoints`](#transcend-inventory-pull-datapoints) - - [`transcend inventory pull-unstructured-discovery-files`](#transcend-inventory-pull-unstructured-discovery-files) - - [`transcend inventory derive-data-silos-from-data-flows`](#transcend-inventory-derive-data-silos-from-data-flows) - - [`transcend inventory derive-data-silos-from-data-flows-cross-instance`](#transcend-inventory-derive-data-silos-from-data-flows-cross-instance) - - [`transcend inventory consent-manager-service-json-to-yml`](#transcend-inventory-consent-manager-service-json-to-yml) - - [`transcend inventory consent-managers-to-business-entities`](#transcend-inventory-consent-managers-to-business-entities) - - [`transcend admin generate-api-keys`](#transcend-admin-generate-api-keys) - - [Usage](#usage-4) - - [`transcend migration sync-ot`](#transcend-migration-sync-ot) + - [`transcend request approve`](#transcend-request-approve) + - [`transcend request upload`](#transcend-request-upload) + - [`transcend request download-files`](#transcend-request-download-files) + - [`transcend request cancel`](#transcend-request-cancel) + - [`transcend request restart`](#transcend-request-restart) + - [`transcend request notify-additional-time`](#transcend-request-notify-additional-time) + - [`transcend request mark-silent`](#transcend-request-mark-silent) + - [`transcend request enricher-restart`](#transcend-request-enricher-restart) + - [`transcend request reject-unverified-identifiers`](#transcend-request-reject-unverified-identifiers) + - [`transcend request export`](#transcend-request-export) + - [`transcend request skip-preflight-jobs`](#transcend-request-skip-preflight-jobs) + - [`transcend request system mark-request-data-silos-completed`](#transcend-request-system-mark-request-data-silos-completed) + - [`transcend request system retry-request-data-silos`](#transcend-request-system-retry-request-data-silos) + - [`transcend request system skip-request-data-silos`](#transcend-request-system-skip-request-data-silos) + - [`transcend request preflight pull-identifiers`](#transcend-request-preflight-pull-identifiers) + - [`transcend request preflight push-identifiers`](#transcend-request-preflight-push-identifiers) + - [`transcend request cron pull-identifiers`](#transcend-request-cron-pull-identifiers) + - [`transcend request cron mark-identifiers-completed`](#transcend-request-cron-mark-identifiers-completed) + - [`transcend consent build-xdi-sync-endpoint`](#transcend-consent-build-xdi-sync-endpoint) + - [`transcend consent pull-consent-metrics`](#transcend-consent-pull-consent-metrics) + - [`transcend consent pull-consent-preferences`](#transcend-consent-pull-consent-preferences) + - [`transcend consent update-consent-manager`](#transcend-consent-update-consent-manager) + - [`transcend consent upload-consent-preferences`](#transcend-consent-upload-consent-preferences) + - [`transcend consent upload-cookies-from-csv`](#transcend-consent-upload-cookies-from-csv) + - [`transcend consent upload-data-flows-from-csv`](#transcend-consent-upload-data-flows-from-csv) + - [`transcend consent upload-preferences`](#transcend-consent-upload-preferences) + - [`transcend inventory pull`](#transcend-inventory-pull) + - [Scopes](#scopes) + - [Usage](#usage-1) + - [`transcend inventory push`](#transcend-inventory-push) + - [Scopes](#scopes-1) + - [Usage](#usage-2) + - [CI Integration](#ci-integration) + - [Dynamic Variables](#dynamic-variables) + - [`transcend inventory scan-packages`](#transcend-inventory-scan-packages) + - [`transcend inventory discover-silos`](#transcend-inventory-discover-silos) + - [Usage](#usage-3) + - [`transcend inventory pull-datapoints`](#transcend-inventory-pull-datapoints) + - [`transcend inventory pull-unstructured-discovery-files`](#transcend-inventory-pull-unstructured-discovery-files) + - [`transcend inventory derive-data-silos-from-data-flows`](#transcend-inventory-derive-data-silos-from-data-flows) + - [`transcend inventory derive-data-silos-from-data-flows-cross-instance`](#transcend-inventory-derive-data-silos-from-data-flows-cross-instance) + - [`transcend inventory consent-manager-service-json-to-yml`](#transcend-inventory-consent-manager-service-json-to-yml) + - [`transcend inventory consent-managers-to-business-entities`](#transcend-inventory-consent-managers-to-business-entities) + - [`transcend admin generate-api-keys`](#transcend-admin-generate-api-keys) + - [Usage](#usage-4) + - [`transcend migration sync-ot`](#transcend-migration-sync-ot) - [Prompt Manager](#prompt-manager) - [Proxy usage](#proxy-usage) @@ -114,8 +114,8 @@ The structure of `transcend.yml` looks something like the following: # CLI, it is possible to specify which API key should be associated # with the newly created data silo. api-keys: - - title: Webhook Key - - title: Analytics Key + - title: Webhook Key + - title: Analytics Key # Manage at: https://app.transcend.io/privacy-requests/identifiers # See https://docs.transcend.io/docs/identity-enrichment @@ -126,65 +126,65 @@ api-keys: # - fraud check: auto-cancel requests if the user is flagged for fraudulent behavior # - customer check: auto-cancel request for some custom business criteria enrichers: - - title: Basic Identity Enrichment - description: Enrich an email address to the userId and phone number - url: https://example.acme.com/transcend-enrichment-webhook - input-identifier: email - output-identifiers: - - userId - - phone - - myUniqueIdentifier - - title: Fraud Check - description: Ensure the email address is not marked as fraudulent - url: https://example.acme.com/transcend-fraud-check - input-identifier: email - output-identifiers: - - email - privacy-actions: - - ERASURE + - title: Basic Identity Enrichment + description: Enrich an email address to the userId and phone number + url: https://example.acme.com/transcend-enrichment-webhook + input-identifier: email + output-identifiers: + - userId + - phone + - myUniqueIdentifier + - title: Fraud Check + description: Ensure the email address is not marked as fraudulent + url: https://example.acme.com/transcend-fraud-check + input-identifier: email + output-identifiers: + - email + privacy-actions: + - ERASURE # Manage at: https://app.transcend.io/privacy-requests/connected-services # See https://docs.transcend.io/docs/the-data-map#data-silos # Define the data silos in your data map. A data silo can be a database, # or a web service that may use a collection of different data stores under the hood. data-silos: - # Note: title is the only required top-level field for a data silo - - title: Redshift Data Warehouse - description: The mega-warehouse that contains a copy over all SQL backed databases - integrationName: server - url: https://example.acme.com/transcend-webhook - api-key-title: Webhook Key - data-subjects: - - customer - - employee - - newsletter-subscriber - - b2b-contact - identity-keys: - - email - - userId - deletion-dependencies: - - Identity Service - owners: - - alice@transcend.io - datapoints: - - title: Webhook Notification - key: _global - privacy-actions: - - ACCESS - - ERASURE - - SALE_OPT_OUT - - title: User Model - description: The centralized user model user - key: users - privacy-actions: - - ACCESS - fields: - - key: firstName - title: First Name - description: The first name of the user, inputted during onboarding - - key: email - title: Email - description: The email address of the user + # Note: title is the only required top-level field for a data silo + - title: Redshift Data Warehouse + description: The mega-warehouse that contains a copy over all SQL backed databases + integrationName: server + url: https://example.acme.com/transcend-webhook + api-key-title: Webhook Key + data-subjects: + - customer + - employee + - newsletter-subscriber + - b2b-contact + identity-keys: + - email + - userId + deletion-dependencies: + - Identity Service + owners: + - alice@transcend.io + datapoints: + - title: Webhook Notification + key: _global + privacy-actions: + - ACCESS + - ERASURE + - SALE_OPT_OUT + - title: User Model + description: The centralized user model user + key: users + privacy-actions: + - ACCESS + fields: + - key: firstName + title: First Name + description: The first name of the user, inputted during onboarding + - key: email + title: Email + description: The email address of the user ``` ## Usage @@ -1133,32 +1133,32 @@ name: Transcend Data Map Syncing # See https://app.transcend.io/privacy-requests/connected-services on: - push: - branches: - - 'main' + push: + branches: + - 'main' jobs: - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 - - name: Setup Node.js - uses: actions/setup-node@v2 - with: - node-version: '16' + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: '16' - - name: Install Transcend CLI - run: npm install --global @transcend-io/cli + - name: Install Transcend CLI + run: npm install --global @transcend-io/cli - # If you have a script that generates your transcend.yml file from - # an ORM or infrastructure configuration, add that step here - # Leave this step commented out if you want to manage your transcend.yml manually - # - name: Generate transcend.yml - # run: ./scripts/generate_transcend_yml.py + # If you have a script that generates your transcend.yml file from + # an ORM or infrastructure configuration, add that step here + # Leave this step commented out if you want to manage your transcend.yml manually + # - name: Generate transcend.yml + # run: ./scripts/generate_transcend_yml.py - - name: Push Transcend config - run: transcend inventory push --auth=${{ secrets.TRANSCEND_API_KEY }} + - name: Push Transcend config + run: transcend inventory push --auth=${{ secrets.TRANSCEND_API_KEY }} ``` #### Dynamic Variables @@ -1175,32 +1175,32 @@ This command could fill out multiple parameters in a YAML file like [./examples/ ```yml api-keys: - - title: Webhook Key + - title: Webhook Key enrichers: - - title: Basic Identity Enrichment - description: Enrich an email address to the userId and phone number - # The data silo webhook URL is the same in each environment, - # except for the base domain in the webhook URL. - url: https://example.<>/transcend-enrichment-webhook - input-identifier: email - output-identifiers: - - userId - - phone - - myUniqueIdentifier - - title: Fraud Check - description: Ensure the email address is not marked as fraudulent - url: https://example.<>/transcend-fraud-check - input-identifier: email - output-identifiers: - - email - privacy-actions: - - ERASURE + - title: Basic Identity Enrichment + description: Enrich an email address to the userId and phone number + # The data silo webhook URL is the same in each environment, + # except for the base domain in the webhook URL. + url: https://example.<>/transcend-enrichment-webhook + input-identifier: email + output-identifiers: + - userId + - phone + - myUniqueIdentifier + - title: Fraud Check + description: Ensure the email address is not marked as fraudulent + url: https://example.<>/transcend-fraud-check + input-identifier: email + output-identifiers: + - email + privacy-actions: + - ERASURE data-silos: - - title: Redshift Data Warehouse - integrationName: server - description: The mega-warehouse that contains a copy over all SQL backed databases - <> - url: https://example.<>/transcend-webhook - api-key-title: Webhook Key + - title: Redshift Data Warehouse + integrationName: server + description: The mega-warehouse that contains a copy over all SQL backed databases - <> + url: https://example.<>/transcend-webhook + api-key-title: Webhook Key ``` ### `transcend inventory scan-packages` @@ -1432,12 +1432,12 @@ Filter for only a specific organization by ID, returning all child accounts asso ```gql query { - user { - organization { - id - parentOrganizationId - } - } + user { + organization { + id + parentOrganizationId + } + } } ``` @@ -1499,142 +1499,145 @@ FLAGS If you are integrating Transcend's Prompt Manager into your code, it may look like: ```ts -import * as t from 'io-ts'; import { TranscendPromptManager } from '@transcend-io/cli'; import { - ChatCompletionMessage, - PromptRunProductArea, + ChatCompletionMessage, + PromptRunProductArea, } from '@transcend-io/privacy-types'; +import * as t from 'io-ts'; /** * Example prompt integration */ export async function main(): Promise { - // Instantiate the Transcend Prompt Manager instance - const promptManager = new TranscendPromptManager({ - // API key - transcendApiKey: process.env.TRANSCEND_API_KEY, - // Define the prompts that are stored in Transcend - prompts: { - test: { - // identify by ID - id: '30bcaa79-889a-4af3-842d-2e8ba443d36d', - // no runtime variables - paramCodec: t.type({}), - // response is list of strings - outputCodec: t.array(t.string), + // Instantiate the Transcend Prompt Manager instance + const promptManager = new TranscendPromptManager({ + // API key + transcendApiKey: process.env.TRANSCEND_API_KEY, + // Define the prompts that are stored in Transcend + prompts: { + test: { + // identify by ID + id: '30bcaa79-889a-4af3-842d-2e8ba443d36d', + // no runtime variables + paramCodec: t.type({}), + // response is list of strings + outputCodec: t.array(t.string), + }, + json: { + // identify by title + title: 'test', + // one runtime variable "test" + paramCodec: t.type({ test: t.string }), + // runtime is json object + outputCodec: t.record(t.string, t.string), + // response is stored in atg + extractFromTag: 'json', + }, + predictProductLine: { + // identify by title + title: 'Predict Product Line', + // runtime parameter for slack channel name + paramCodec: t.type({ + slackChannelName: t.string, + }), + // response is specific JSON shape + outputCodec: t.type({ + product: t.union([t.string, t.null]), + clarification: t.union([t.string, t.null]), + }), + // response is stored in atg + extractFromTag: 'json', + }, + }, + // Optional arguments + // transcendUrl: 'https://api.us.transcend.io', // defaults to 'https://api.transcend.io' + // requireApproval: false, // defaults to true + // cacheDuration: 1000 * 60 * 60, // defaults to undefined, no cache + // defaultVariables: { myVariable: 'this is custom', other: [{ name: 'custom' }] }, // defaults to {} + // handlebarsOptions: { helpers, templates }, // defaults to {} + }); + + // Fetch the prompt from Transcend and template any variables + // in this case, we template the slack channel name in the LLM prompt + const systemPrompt = await promptManager.compilePrompt( + 'predictProductLine', + { + slackChannelName: channelName, + }, + ); + + // Parameters to pass to the LLM + const input: ChatCompletionMessage[] = [ + { + role: 'system', + content: systemPrompt, }, - json: { - // identify by title - title: 'test', - // one runtime variable "test" - paramCodec: t.type({ test: t.string }), - // runtime is json object - outputCodec: t.record(t.string, t.string), - // response is stored in atg - extractFromTag: 'json', + { + role: 'user', + content: input, }, - predictProductLine: { - // identify by title - title: 'Predict Product Line', - // runtime parameter for slack channel name - paramCodec: t.type({ - slackChannelName: t.string, - }), - // response is specific JSON shape - outputCodec: t.type({ - product: t.union([t.string, t.null]), - clarification: t.union([t.string, t.null]), - }), - // response is stored in atg - extractFromTag: 'json', + ]; + const largeLanguageModel = { + name: 'gpt-4', + client: 'openai' as const, + }; + const temperature = 1; + const topP = 1; + const maxTokensToSample = 1000; + + // Run prompt against LLM + let response: string; + const t0 = new Date().getTime(); + try { + response = await openai.createCompletion(input, { + temperature, + top_p: topP, + max_tokens: maxTokensToSample, + }); + } catch (err) { + // report error upon failure + await promptManager.reportPromptRunError('predictProductLine', { + promptRunMessages: input, + duration: new Date().getTime() - t0, + temperature, + topP, + error: err.message, + maxTokensToSample, + largeLanguageModel, + }); + } + const t1 = new Date().getTime(); + + // Parsed response as JSON and do not report to Transcend + // const parsedResponse = promptManager.parseAiResponse( + // 'predictProductLine', + // response, + // ); + + // Parsed response as JSON and report output to Transcend + const parsedResponse = await promptManager.reportAndParsePromptRun( + 'predictProductLine', + { + promptRunMessages: [ + ...input, + { + role: 'assistant', + content: response, + }, + ], + duration: t1 - t0, + temperature, + topP, + maxTokensToSample, + largeLanguageModel, + // Optional parameters + // name, // unique identifier for this run + // productArea, // Transcend product area that the prompt relates to + // runByEmployeeEmail, // Employee email that is executing the request + // promptGroupId, // The prompt group being reported }, - }, - // Optional arguments - // transcendUrl: 'https://api.us.transcend.io', // defaults to 'https://api.transcend.io' - // requireApproval: false, // defaults to true - // cacheDuration: 1000 * 60 * 60, // defaults to undefined, no cache - // defaultVariables: { myVariable: 'this is custom', other: [{ name: 'custom' }] }, // defaults to {} - // handlebarsOptions: { helpers, templates }, // defaults to {} - }); - - // Fetch the prompt from Transcend and template any variables - // in this case, we template the slack channel name in the LLM prompt - const systemPrompt = await promptManager.compilePrompt('predictProductLine', { - slackChannelName: channelName, - }); - - // Parameters to pass to the LLM - const input: ChatCompletionMessage[] = [ - { - role: 'system', - content: systemPrompt, - }, - { - role: 'user', - content: input, - }, - ]; - const largeLanguageModel = { - name: 'gpt-4', - client: 'openai' as const, - }; - const temperature = 1; - const topP = 1; - const maxTokensToSample = 1000; - - // Run prompt against LLM - let response: string; - const t0 = new Date().getTime(); - try { - response = await openai.createCompletion(input, { - temperature, - top_p: topP, - max_tokens: maxTokensToSample, - }); - } catch (err) { - // report error upon failure - await promptManager.reportPromptRunError('predictProductLine', { - promptRunMessages: input, - duration: new Date().getTime() - t0, - temperature, - topP, - error: err.message, - maxTokensToSample, - largeLanguageModel, - }); - } - const t1 = new Date().getTime(); - - // Parsed response as JSON and do not report to Transcend - // const parsedResponse = promptManager.parseAiResponse( - // 'predictProductLine', - // response, - // ); - - // Parsed response as JSON and report output to Transcend - const parsedResponse = await promptManager.reportAndParsePromptRun( - 'predictProductLine', - { - promptRunMessages: [ - ...input, - { - role: 'assistant', - content: response, - }, - ], - duration: t1 - t0, - temperature, - topP, - maxTokensToSample, - largeLanguageModel, - // Optional parameters - // name, // unique identifier for this run - // productArea, // Transcend product area that the prompt relates to - // runByEmployeeEmail, // Employee email that is executing the request - // promptGroupId, // The prompt group being reported - }, - ); + ); } ``` diff --git a/scripts/buildPathfinderJsonSchema.ts b/scripts/buildPathfinderJsonSchema.ts index ca0562c8..ba22da89 100644 --- a/scripts/buildPathfinderJsonSchema.ts +++ b/scripts/buildPathfinderJsonSchema.ts @@ -12,8 +12,8 @@ * @see https://github.com/SchemaStore/schemastore */ -import { writeFileSync } from 'fs'; -import { join } from 'path'; +import { writeFileSync } from 'node:fs'; +import { join } from 'node:path'; import { toJsonSchema } from '@transcend-io/type-utils'; import { PathfinderPolicy } from '../src/codecs'; diff --git a/scripts/buildReadmeDocs.ts b/scripts/buildReadmeDocs.ts index 20d8c66a..c02b9cb9 100644 --- a/scripts/buildReadmeDocs.ts +++ b/scripts/buildReadmeDocs.ts @@ -1,15 +1,14 @@ +import { execSync } from 'node:child_process'; +import fs from 'node:fs'; import { generateHelpTextForAllCommands, type Application, type CommandContext, } from '@stricli/core'; -import { app } from '../src/app'; -import fs from 'node:fs'; -import { execSync } from 'node:child_process'; import { fdir } from 'fdir'; +import { app } from '../src/app'; -// eslint-disable-next-line new-cap -const docFiles = new fdir() +const documentFiles = new fdir() .withRelativePaths() .glob('**/readme.ts') .crawl('./src/commands') @@ -18,7 +17,7 @@ const docFiles = new fdir() // For each src/commands/**/readme.ts file, create a key-value pair of the command and the exported Markdown documentation const additionalDocumentation: Record = Object.fromEntries( await Promise.all( - docFiles.map(async (file) => { + documentFiles.map(async (file) => { const command = `transcend ${file.split('/').slice(0, -1).join(' ')}`; const readme = (await import(`../src/commands/${file}`)).default; return [command, readme]; @@ -42,7 +41,7 @@ const formattedMarkdown: string = helpTextForAllCommands const readme = fs.readFileSync('README.md', 'utf8'); -const newReadme = readme.replace( +const newReadme = readme.replaceAll( /[\s\S]*?/g, `\n${formattedMarkdown}\n`, ); diff --git a/scripts/buildTranscendJsonSchema.ts b/scripts/buildTranscendJsonSchema.ts index d6b8a897..9c00ec6c 100644 --- a/scripts/buildTranscendJsonSchema.ts +++ b/scripts/buildTranscendJsonSchema.ts @@ -12,8 +12,8 @@ * @see https://github.com/SchemaStore/schemastore */ -import { writeFileSync } from 'fs'; -import { join } from 'path'; +import { writeFileSync } from 'node:fs'; +import { join } from 'node:path'; import { toJsonSchema } from '@transcend-io/type-utils'; import * as packageJson from '../package.json'; import { TranscendInput } from '../src/codecs'; @@ -21,7 +21,7 @@ import { TranscendInput } from '../src/codecs'; const majorVersion = packageJson.version.split('.')[0]; // Create a major version JSON schema definition, and update the latest JSON schema definition. -[`v${majorVersion}`, 'latest'].forEach((key) => { +for (const key of [`v${majorVersion}`, 'latest']) { const fileName = `transcend-yml-schema-${key}.json`; const schemaDefaults = { @@ -38,4 +38,4 @@ const majorVersion = packageJson.version.split('.')[0]; const schemaFilePath = join(process.cwd(), fileName); writeFileSync(schemaFilePath, `${JSON.stringify(jsonSchema, null, 2)}\n`); -}); +} diff --git a/src/codecs.ts b/src/codecs.ts index b9f3b1f6..c1d8342c 100644 --- a/src/codecs.ts +++ b/src/codecs.ts @@ -1,69 +1,69 @@ // eslint-disable-next-line eslint-comments/disable-enable-pair -/* eslint-disable max-lines */ -import * as t from 'io-ts'; -import { applyEnum, valuesOf } from '@transcend-io/type-utils'; + import { - DataCategoryType, - ConsentBundleType, - EnricherType, - ProcessingPurpose, - RequestAction, - ComparisonOperator, - RequestActionObjectResolver, - AssessmentSyncColumn, - RetentionScheduleType, + BrowserLanguage, + InitialViewState, + OnConsentExpiry, + UserPrivacySignalEnum, +} from '@transcend-io/airgap.js-types'; +import { LanguageKey } from '@transcend-io/internationalization'; +import { + ActionItemCode, + ActionItemPriorityOverride, + AssessmentFormStatus, + AssessmentFormTemplateSource, + AssessmentFormTemplateStatus, + AssessmentQuestionSubType, AssessmentQuestionType, - UspapiOption, - DataFlowScope, - PromptAVendorEmailSendType, - RetentionScheduleOperation, AssessmentsDisplayLogicAction, - DefaultConsentOption, - LogicOperator, - ConsentPrecedenceOption, + AssessmentSyncColumn, AssessmentSyncModel, - AssessmentQuestionSubType, - IsoCountryCode, + AttributeKeyType, + AttributeSupportedResourceType, BrowserTimeZone, - IsoCountrySubdivisionCode, + CodePackageType, + ComparisonOperator, + ConfigurableColorPaletteColor, + ConsentBundleType, + ConsentPrecedenceOption, ConsentTrackerStatus, - AttributeKeyType, + DataCategoryType, + DataFlowScope, + DefaultConsentOption, + EnricherType, + IsoCountryCode, + IsoCountrySubdivisionCode, + LargeLanguageModelClient, + LogicOperator, + PreferenceStoreAuthLevel, + PreferenceTopicType, + PreflightRequestStatus, + PrivacyCenterComponentStyles, + PrivacyCenterTextStyles, + ProcessingPurpose, PromptAVendorEmailCompletionLinkType, + PromptAVendorEmailSendType, + PromptFilePurpose, + RegionDetectionMethod, RegionsOperator, - UnknownRequestPolicy, - TelemetryPartitionStrategy, + RequestAction, + RequestActionObjectResolver, + RetentionScheduleOperation, + RetentionScheduleType, + ScopeName, SignedIabAgreementOption, - RegionDetectionMethod, - PreflightRequestStatus, - AttributeSupportedResourceType, SubDataPointDataSubCategoryGuessStatus, - LargeLanguageModelClient, - PromptFilePurpose, - CodePackageType, - ActionItemPriorityOverride, - ActionItemCode, - ScopeName, + TelemetryPartitionStrategy, TranscendProduct, - PrivacyCenterComponentStyles, - PrivacyCenterTextStyles, - PreferenceStoreAuthLevel, - ConfigurableColorPaletteColor, - AssessmentFormTemplateStatus, - AssessmentFormStatus, - AssessmentFormTemplateSource, + UnknownRequestPolicy, UnstructuredSubDataPointRecommendationStatus, - PreferenceTopicType, + UspapiOption, } from '@transcend-io/privacy-types'; -import { - InitialViewState, - BrowserLanguage, - UserPrivacySignalEnum, - OnConsentExpiry, -} from '@transcend-io/airgap.js-types'; -import { buildEnabledRouteType } from './lib/helpers/buildEnabledRouteType'; -import { buildAIIntegrationType } from './lib/helpers/buildAIIntegrationType'; +import { applyEnum, valuesOf } from '@transcend-io/type-utils'; +import * as t from 'io-ts'; import { OpenAIRouteName, PathfinderPolicyName } from './enums'; -import { LanguageKey } from '@transcend-io/internationalization'; +import { buildAIIntegrationType } from './lib/helpers/buildAIIntegrationType'; +import { buildEnabledRouteType } from './lib/helpers/buildEnabledRouteType'; /** * Input to define email templates that can be used to communicate to end-users diff --git a/src/commands/admin/generate-api-keys/impl.ts b/src/commands/admin/generate-api-keys/impl.ts index 1e15be84..0288e38e 100644 --- a/src/commands/admin/generate-api-keys/impl.ts +++ b/src/commands/admin/generate-api-keys/impl.ts @@ -1,12 +1,10 @@ -import type { LocalContext } from '../../../context'; -import colors from 'colors'; -import { writeFileSync } from 'fs'; - +import { writeFileSync } from 'node:fs'; import { ScopeName, TRANSCEND_SCOPES } from '@transcend-io/privacy-types'; - -import { logger } from '../../../logger'; -import { generateCrossAccountApiKeys } from '../../../lib/api-keys'; +import colors from 'colors'; import { keyBy } from 'lodash-es'; +import type { LocalContext } from '../../../context'; +import { generateCrossAccountApiKeys } from '../../../lib/api-keys'; +import { logger } from '../../../logger'; const SCOPES_BY_TITLE = keyBy( Object.entries(TRANSCEND_SCOPES).map(([name, value]) => ({ diff --git a/src/commands/consent/build-xdi-sync-endpoint/impl.ts b/src/commands/consent/build-xdi-sync-endpoint/impl.ts index d930bf53..b42f26bb 100644 --- a/src/commands/consent/build-xdi-sync-endpoint/impl.ts +++ b/src/commands/consent/build-xdi-sync-endpoint/impl.ts @@ -1,9 +1,9 @@ -import type { LocalContext } from '../../../context'; -import { logger } from '../../../logger'; +import { writeFileSync } from 'node:fs'; import colors from 'colors'; -import { writeFileSync } from 'fs'; +import type { LocalContext } from '../../../context'; import { validateTranscendAuth } from '../../../lib/api-keys'; import { buildXdiSyncEndpoint as buildXdiSyncEndpointHelper } from '../../../lib/consent-manager'; +import { logger } from '../../../logger'; interface BuildXdiSyncEndpointCommandFlags { auth: string; diff --git a/src/commands/consent/pull-consent-metrics/impl.ts b/src/commands/consent/pull-consent-metrics/impl.ts index 5efea655..0b1c58b2 100644 --- a/src/commands/consent/pull-consent-metrics/impl.ts +++ b/src/commands/consent/pull-consent-metrics/impl.ts @@ -1,17 +1,17 @@ -import type { LocalContext } from '../../../context'; -import { logger } from '../../../logger'; +import fs, { existsSync, mkdirSync } from 'node:fs'; +import { join } from 'node:path'; import colors from 'colors'; +import { ADMIN_DASH_INTEGRATIONS } from '../../../constants'; +import type { LocalContext } from '../../../context'; +import { validateTranscendAuth } from '../../../lib/api-keys'; import { mapSeries } from '../../../lib/bluebird-replace'; -import { join } from 'path'; -import fs, { existsSync, mkdirSync } from 'fs'; +import { pullConsentManagerMetrics } from '../../../lib/consent-manager'; +import { writeCsv } from '../../../lib/cron'; import { buildTranscendGraphQLClient, ConsentManagerMetricBin, } from '../../../lib/graphql'; -import { validateTranscendAuth } from '../../../lib/api-keys'; -import { ADMIN_DASH_INTEGRATIONS } from '../../../constants'; -import { pullConsentManagerMetrics } from '../../../lib/consent-manager'; -import { writeCsv } from '../../../lib/cron'; +import { logger } from '../../../logger'; interface PullConsentMetricsCommandFlags { auth: string; @@ -114,8 +114,8 @@ export async function pullConsentMetrics( }); // Write to file - Object.entries(configuration).forEach(([metricName, metrics]) => { - metrics.forEach(({ points, name }) => { + for (const [metricName, metrics] of Object.entries(configuration)) { + for (const { points, name } of metrics) { const file = join(folder, `${metricName}_${name}.csv`); logger.info( colors.magenta(`Writing configuration to file "${file}"...`), @@ -127,11 +127,11 @@ export async function pullConsentMetrics( value, })), ); - }); - }); - } catch (err) { + } + } + } catch (error) { logger.error( - colors.red(`An error occurred syncing the schema: ${err.message}`), + colors.red(`An error occurred syncing the schema: ${error.message}`), ); process.exit(1); } @@ -171,8 +171,8 @@ export async function pullConsentMetrics( } // Write to file - Object.entries(configuration).forEach(([metricName, metrics]) => { - metrics.forEach(({ points, name }) => { + for (const [metricName, metrics] of Object.entries(configuration)) { + for (const { points, name } of metrics) { const file = join(subFolder, `${metricName}_${name}.csv`); logger.info( colors.magenta(`Writing configuration to file "${file}"...`), @@ -184,13 +184,13 @@ export async function pullConsentMetrics( value, })), ); - }); - }); + } + } logger.info( colors.green(`${prefix}Successfully pulled configuration!`), ); - } catch (err) { + } catch { logger.error(colors.red(`${prefix}Failed to sync configuration.`)); encounteredErrors.push(apiKey.organizationName); } diff --git a/src/commands/consent/pull-consent-preferences/impl.ts b/src/commands/consent/pull-consent-preferences/impl.ts index aaf4b6fe..afb94a29 100644 --- a/src/commands/consent/pull-consent-preferences/impl.ts +++ b/src/commands/consent/pull-consent-preferences/impl.ts @@ -1,5 +1,4 @@ import type { LocalContext } from '../../../context'; - import { fetchConsentPreferences } from '../../../lib/consent-manager'; import { writeCsv } from '../../../lib/cron'; import { createSombraGotInstance } from '../../../lib/graphql'; diff --git a/src/commands/consent/update-consent-manager/impl.ts b/src/commands/consent/update-consent-manager/impl.ts index 7b549293..25ae2763 100644 --- a/src/commands/consent/update-consent-manager/impl.ts +++ b/src/commands/consent/update-consent-manager/impl.ts @@ -1,11 +1,10 @@ -import type { LocalContext } from '../../../context'; -import colors from 'colors'; import { ConsentBundleType } from '@transcend-io/privacy-types'; +import colors from 'colors'; +import type { LocalContext } from '../../../context'; +import { validateTranscendAuth } from '../../../lib/api-keys'; import { mapSeries } from '../../../lib/bluebird-replace'; - -import { logger } from '../../../logger'; import { updateConsentManagerVersionToLatest } from '../../../lib/consent-manager'; -import { validateTranscendAuth } from '../../../lib/api-keys'; +import { logger } from '../../../logger'; interface UpdateConsentManagerCommandFlags { auth: string; diff --git a/src/commands/consent/upload-consent-preferences/impl.ts b/src/commands/consent/upload-consent-preferences/impl.ts index 365a7f72..267f2ee9 100644 --- a/src/commands/consent/upload-consent-preferences/impl.ts +++ b/src/commands/consent/upload-consent-preferences/impl.ts @@ -1,7 +1,6 @@ import type { LocalContext } from '../../../context'; - -import { uploadConsents } from '../../../lib/consent-manager/uploadConsents'; import { ConsentPreferenceUpload } from '../../../lib/consent-manager/types'; +import { uploadConsents } from '../../../lib/consent-manager/uploadConsents'; import { readCsv } from '../../../lib/requests'; interface UploadConsentPreferencesCommandFlags { diff --git a/src/commands/consent/upload-cookies-from-csv/impl.ts b/src/commands/consent/upload-cookies-from-csv/impl.ts index 117b44b0..3e716dea 100644 --- a/src/commands/consent/upload-cookies-from-csv/impl.ts +++ b/src/commands/consent/upload-cookies-from-csv/impl.ts @@ -1,6 +1,6 @@ +import { ConsentTrackerStatus } from '@transcend-io/privacy-types'; import type { LocalContext } from '../../../context'; import { uploadCookiesFromCsv as uploadCookiesFromCsvHelper } from '../../../lib/consent-manager'; -import { ConsentTrackerStatus } from '@transcend-io/privacy-types'; interface UploadCookiesFromCsvCommandFlags { auth: string; diff --git a/src/commands/consent/upload-data-flows-from-csv/impl.ts b/src/commands/consent/upload-data-flows-from-csv/impl.ts index c65edaa9..e1cfd34e 100644 --- a/src/commands/consent/upload-data-flows-from-csv/impl.ts +++ b/src/commands/consent/upload-data-flows-from-csv/impl.ts @@ -1,6 +1,6 @@ +import { ConsentTrackerStatus } from '@transcend-io/privacy-types'; import type { LocalContext } from '../../../context'; import { uploadDataFlowsFromCsv as uploadDataFlowsFromCsvHelper } from '../../../lib/consent-manager'; -import { ConsentTrackerStatus } from '@transcend-io/privacy-types'; interface UploadDataFlowsFromCsvCommandFlags { auth: string; diff --git a/src/commands/consent/upload-preferences/impl.ts b/src/commands/consent/upload-preferences/impl.ts index eace39ac..d8c64d03 100644 --- a/src/commands/consent/upload-preferences/impl.ts +++ b/src/commands/consent/upload-preferences/impl.ts @@ -1,12 +1,11 @@ -import type { LocalContext } from '../../../context'; +import { readdirSync } from 'node:fs'; +import { basename, join } from 'node:path'; import colors from 'colors'; - -import { logger } from '../../../logger'; +import type { LocalContext } from '../../../context'; +import { map } from '../../../lib/bluebird-replace'; import { uploadPreferenceManagementPreferencesInteractive } from '../../../lib/preference-management'; import { splitCsvToList } from '../../../lib/requests'; -import { readdirSync } from 'fs'; -import { map } from '../../../lib/bluebird-replace'; -import { basename, join } from 'path'; +import { logger } from '../../../logger'; interface UploadPreferencesCommandFlags { auth: string; @@ -81,9 +80,9 @@ export async function uploadPreferences( // Add full paths for each CSV file files.push(...csvFiles.map((file) => join(directory, file))); - } catch (err) { + } catch (error) { logger.error(colors.red(`Failed to read directory: ${directory}`)); - logger.error(colors.red((err as Error).message)); + logger.error(colors.red((error as Error).message)); process.exit(1); } } else { @@ -94,9 +93,9 @@ export async function uploadPreferences( process.exit(1); } files.push(file); - } catch (err) { + } catch (error) { logger.error(colors.red(`Failed to access file: ${file}`)); - logger.error(colors.red((err as Error).message)); + logger.error(colors.red((error as Error).message)); process.exit(1); } } diff --git a/src/commands/inventory/consent-manager-service-json-to-yml/command.ts b/src/commands/inventory/consent-manager-service-json-to-yml/command.ts index 248474e8..faa662b1 100644 --- a/src/commands/inventory/consent-manager-service-json-to-yml/command.ts +++ b/src/commands/inventory/consent-manager-service-json-to-yml/command.ts @@ -1,5 +1,5 @@ -import { name } from '../../../constants'; import { buildCommand } from '@stricli/core'; +import { name } from '../../../constants'; export const consentManagerServiceJsonToYmlCommand = buildCommand({ loader: async () => { diff --git a/src/commands/inventory/consent-manager-service-json-to-yml/impl.ts b/src/commands/inventory/consent-manager-service-json-to-yml/impl.ts index 39697da0..28ab8b64 100644 --- a/src/commands/inventory/consent-manager-service-json-to-yml/impl.ts +++ b/src/commands/inventory/consent-manager-service-json-to-yml/impl.ts @@ -1,19 +1,19 @@ -import type { LocalContext } from '../../../context'; -import * as t from 'io-ts'; -import { writeTranscendYaml } from '../../../lib/readTranscendYaml'; -import colors from 'colors'; -import { logger } from '../../../logger'; -import { existsSync, readFileSync } from 'fs'; +import { existsSync, readFileSync } from 'node:fs'; +import { + ConsentTrackerStatus, + DataFlowScope, +} from '@transcend-io/privacy-types'; import { decodeCodec } from '@transcend-io/type-utils'; +import colors from 'colors'; +import * as t from 'io-ts'; import { ConsentManagerServiceMetadata, CookieInput, DataFlowInput, } from '../../../codecs'; -import { - ConsentTrackerStatus, - DataFlowScope, -} from '@transcend-io/privacy-types'; +import type { LocalContext } from '../../../context'; +import { writeTranscendYaml } from '../../../lib/readTranscendYaml'; +import { logger } from '../../../logger'; interface ConsentManagerServiceJsonToYmlCommandFlags { file: string; @@ -39,26 +39,26 @@ export function consentManagerServiceJsonToYml( // Create data flows and cookie configurations const dataFlows: DataFlowInput[] = []; const cookies: CookieInput[] = []; - services.forEach((service) => { - service.dataFlows - .filter(({ type }) => type !== DataFlowScope.CSP) - .forEach((dataFlow) => { - dataFlows.push({ - value: dataFlow.value, - type: dataFlow.type, - status: ConsentTrackerStatus.Live, - trackingPurposes: dataFlow.trackingPurposes, - }); + for (const service of services) { + for (const dataFlow of service.dataFlows.filter( + ({ type }) => type !== DataFlowScope.CSP, + )) { + dataFlows.push({ + value: dataFlow.value, + type: dataFlow.type, + status: ConsentTrackerStatus.Live, + trackingPurposes: dataFlow.trackingPurposes, }); + } - service.cookies.forEach((cookie) => { + for (const cookie of service.cookies) { cookies.push({ name: cookie.name, status: ConsentTrackerStatus.Live, trackingPurposes: cookie.trackingPurposes, }); - }); - }); + } + } // write to disk writeTranscendYaml(output, { diff --git a/src/commands/inventory/consent-managers-to-business-entities/impl.ts b/src/commands/inventory/consent-managers-to-business-entities/impl.ts index 9d47ffce..e379557a 100644 --- a/src/commands/inventory/consent-managers-to-business-entities/impl.ts +++ b/src/commands/inventory/consent-managers-to-business-entities/impl.ts @@ -1,3 +1,6 @@ +import { existsSync, lstatSync } from 'node:fs'; +import { join } from 'node:path'; +import colors from 'colors'; import type { LocalContext } from '../../../context'; import { listFiles } from '../../../lib/api-keys'; import { consentManagersToBusinessEntities as consentManagersToBusinessEntitiesHelper } from '../../../lib/consent-manager'; @@ -5,11 +8,7 @@ import { readTranscendYaml, writeTranscendYaml, } from '../../../lib/readTranscendYaml'; -import { join } from 'path'; - -import colors from 'colors'; import { logger } from '../../../logger'; -import { existsSync, lstatSync } from 'fs'; interface ConsentManagersToBusinessEntitiesCommandFlags { consentManagerYmlFolder: string; diff --git a/src/commands/inventory/derive-data-silos-from-data-flows-cross-instance/impl.ts b/src/commands/inventory/derive-data-silos-from-data-flows-cross-instance/impl.ts index 6425c764..9b29f0ba 100644 --- a/src/commands/inventory/derive-data-silos-from-data-flows-cross-instance/impl.ts +++ b/src/commands/inventory/derive-data-silos-from-data-flows-cross-instance/impl.ts @@ -1,20 +1,20 @@ +import { existsSync, lstatSync } from 'node:fs'; +import { join } from 'node:path'; +import colors from 'colors'; +import { difference } from 'lodash-es'; +import { DataFlowInput } from '../../../codecs'; import type { LocalContext } from '../../../context'; +import { listFiles } from '../../../lib/api-keys'; +import { dataFlowsToDataSilos } from '../../../lib/consent-manager/dataFlowsToDataSilos'; import { - fetchAndIndexCatalogs, buildTranscendGraphQLClient, + fetchAndIndexCatalogs, } from '../../../lib/graphql'; -import { join } from 'path'; -import { difference } from 'lodash-es'; -import colors from 'colors'; -import { logger } from '../../../logger'; -import { dataFlowsToDataSilos } from '../../../lib/consent-manager/dataFlowsToDataSilos'; -import { DataFlowInput } from '../../../codecs'; -import { existsSync, lstatSync } from 'fs'; -import { listFiles } from '../../../lib/api-keys'; import { readTranscendYaml, writeTranscendYaml, } from '../../../lib/readTranscendYaml'; +import { logger } from '../../../logger'; interface DeriveDataSilosFromDataFlowsCrossInstanceCommandFlags { auth: string; @@ -65,7 +65,7 @@ export async function deriveDataSilosFromDataFlowsCrossInstance( // map the data flows to data silos const { adTechDataSilos, siteTechDataSilos } = dataFlowsToDataSilos( - dataFlows as DataFlowInput[], + dataFlows, { serviceToSupportedIntegration, serviceToTitle, @@ -80,32 +80,32 @@ export async function deriveDataSilosFromDataFlowsCrossInstance( }); // Mapping from service name to instances that have that service - const serviceToInstance: { [k in string]: string[] } = {}; - dataSiloInputs.forEach( - ({ adTechDataSilos, siteTechDataSilos, organizationName }) => { - const allDataSilos = [...adTechDataSilos, ...siteTechDataSilos]; - allDataSilos.forEach((dataSilo) => { - const service = dataSilo['outer-type'] || dataSilo.integrationName; - // create mapping to instance - if (!serviceToInstance[service]) { - serviceToInstance[service] = []; - } - serviceToInstance[service]!.push(organizationName); - serviceToInstance[service] = [...new Set(serviceToInstance[service])]; - }); - }, - ); + const serviceToInstance: Record = {}; + for (const { + adTechDataSilos, + siteTechDataSilos, + organizationName, + } of dataSiloInputs) { + const allDataSilos = [...adTechDataSilos, ...siteTechDataSilos]; + for (const dataSilo of allDataSilos) { + const service = dataSilo['outer-type'] || dataSilo.integrationName; + // create mapping to instance + if (!serviceToInstance[service]) { + serviceToInstance[service] = []; + } + serviceToInstance[service].push(organizationName); + serviceToInstance[service] = [...new Set(serviceToInstance[service])]; + } + } // List of ad tech integrations const adTechIntegrations = [ ...new Set( - dataSiloInputs - .map(({ adTechDataSilos }) => - adTechDataSilos.map( - (silo) => silo['outer-type'] || silo.integrationName, - ), - ) - .flat(), + dataSiloInputs.flatMap(({ adTechDataSilos }) => + adTechDataSilos.map( + (silo) => silo['outer-type'] || silo.integrationName, + ), + ), ), ]; @@ -113,37 +113,35 @@ export async function deriveDataSilosFromDataFlowsCrossInstance( const siteTechIntegrations = difference( [ ...new Set( - dataSiloInputs - .map(({ siteTechDataSilos }) => - siteTechDataSilos.map( - (silo) => silo['outer-type'] || silo.integrationName, - ), - ) - .flat(), + dataSiloInputs.flatMap(({ siteTechDataSilos }) => + siteTechDataSilos.map( + (silo) => silo['outer-type'] || silo.integrationName, + ), + ), ), ], adTechIntegrations, ); // Mapping from service name to list of - const serviceToFoundOnDomain: { [k in string]: string[] } = {}; - dataSiloInputs.forEach(({ adTechDataSilos, siteTechDataSilos }) => { + const serviceToFoundOnDomain: Record = {}; + for (const { adTechDataSilos, siteTechDataSilos } of dataSiloInputs) { const allDataSilos = [...adTechDataSilos, ...siteTechDataSilos]; - allDataSilos.forEach((dataSilo) => { + for (const dataSilo of allDataSilos) { const service = dataSilo['outer-type'] || dataSilo.integrationName; const foundOnDomain = dataSilo.attributes?.find( - (attr) => attr.key === 'Found On Domain', + (attribute) => attribute.key === 'Found On Domain', ); // create mapping to instance if (!serviceToFoundOnDomain[service]) { serviceToFoundOnDomain[service] = []; } - serviceToFoundOnDomain[service]!.push(...(foundOnDomain?.values || [])); + serviceToFoundOnDomain[service].push(...(foundOnDomain?.values || [])); serviceToFoundOnDomain[service] = [ ...new Set(serviceToFoundOnDomain[service]), ]; - }); - }); + } + } // Fetch all integrations in the catalog const client = buildTranscendGraphQLClient(transcendUrl, auth); diff --git a/src/commands/inventory/derive-data-silos-from-data-flows/impl.ts b/src/commands/inventory/derive-data-silos-from-data-flows/impl.ts index 71541d35..27bb7b51 100644 --- a/src/commands/inventory/derive-data-silos-from-data-flows/impl.ts +++ b/src/commands/inventory/derive-data-silos-from-data-flows/impl.ts @@ -1,19 +1,19 @@ +import { existsSync, lstatSync } from 'node:fs'; +import { join } from 'node:path'; +import colors from 'colors'; +import { DataFlowInput } from '../../../codecs'; import type { LocalContext } from '../../../context'; +import { listFiles } from '../../../lib/api-keys'; +import { dataFlowsToDataSilos } from '../../../lib/consent-manager/dataFlowsToDataSilos'; import { - fetchAndIndexCatalogs, buildTranscendGraphQLClient, + fetchAndIndexCatalogs, } from '../../../lib/graphql'; -import { join } from 'path'; -import colors from 'colors'; -import { logger } from '../../../logger'; -import { dataFlowsToDataSilos } from '../../../lib/consent-manager/dataFlowsToDataSilos'; -import { DataFlowInput } from '../../../codecs'; -import { existsSync, lstatSync } from 'fs'; -import { listFiles } from '../../../lib/api-keys'; import { readTranscendYaml, writeTranscendYaml, } from '../../../lib/readTranscendYaml'; +import { logger } from '../../../logger'; interface DeriveDataSilosFromDataFlowsCommandFlags { auth: string; @@ -77,7 +77,7 @@ export async function deriveDataSilosFromDataFlows( await fetchAndIndexCatalogs(client); // List of each data flow yml file - listFiles(dataFlowsYmlFolder).forEach((directory) => { + for (const directory of listFiles(dataFlowsYmlFolder)) { // read in the data flows for a specific instance const { 'data-flows': dataFlows = [] } = readTranscendYaml( join(dataFlowsYmlFolder, directory), @@ -85,7 +85,7 @@ export async function deriveDataSilosFromDataFlows( // map the data flows to data silos const { adTechDataSilos, siteTechDataSilos } = dataFlowsToDataSilos( - dataFlows as DataFlowInput[], + dataFlows, { serviceToSupportedIntegration, serviceToTitle, @@ -100,5 +100,5 @@ export async function deriveDataSilosFromDataFlows( writeTranscendYaml(join(dataSilosYmlFolder, directory), { 'data-silos': ignoreYmls.includes(directory) ? [] : dataSilos, }); - }); + } } diff --git a/src/commands/inventory/discover-silos/impl.ts b/src/commands/inventory/discover-silos/impl.ts index 89ad545e..57341841 100644 --- a/src/commands/inventory/discover-silos/impl.ts +++ b/src/commands/inventory/discover-silos/impl.ts @@ -1,15 +1,15 @@ -import type { LocalContext } from '../../../context'; -import { stringify } from 'query-string'; -import { logger } from '../../../logger'; import colors from 'colors'; +import { stringify } from 'query-string'; import { ADMIN_DASH } from '../../../constants'; +import type { LocalContext } from '../../../context'; +import { SILO_DISCOVERY_CONFIGS } from '../../../lib/code-scanning'; +import { findFilesToScan } from '../../../lib/code-scanning/findFilesToScan'; import { - fetchActiveSiloDiscoPlugin, buildTranscendGraphQLClient, + fetchActiveSiloDiscoPlugin, uploadSiloDiscoveryResults, } from '../../../lib/graphql'; -import { findFilesToScan } from '../../../lib/code-scanning/findFilesToScan'; -import { SILO_DISCOVERY_CONFIGS } from '../../../lib/code-scanning'; +import { logger } from '../../../logger'; interface DiscoverSilosCommandFlags { scanPath: string; diff --git a/src/commands/inventory/pull-datapoints/impl.ts b/src/commands/inventory/pull-datapoints/impl.ts index 682d979c..a76b656a 100644 --- a/src/commands/inventory/pull-datapoints/impl.ts +++ b/src/commands/inventory/pull-datapoints/impl.ts @@ -1,13 +1,12 @@ -import type { LocalContext } from '../../../context'; -import { uniq, groupBy } from 'lodash-es'; - -import { logger } from '../../../logger'; +import { DataCategoryType } from '@transcend-io/privacy-types'; import colors from 'colors'; -import { buildTranscendGraphQLClient } from '../../../lib/graphql'; +import { groupBy, uniq } from 'lodash-es'; import { ADMIN_DASH_DATAPOINTS } from '../../../constants'; -import { pullAllDatapoints } from '../../../lib/data-inventory'; +import type { LocalContext } from '../../../context'; import { writeCsv } from '../../../lib/cron'; -import { DataCategoryType } from '@transcend-io/privacy-types'; +import { pullAllDatapoints } from '../../../lib/data-inventory'; +import { buildTranscendGraphQLClient } from '../../../lib/graphql'; +import { logger } from '../../../logger'; interface PullDatapointsCommandFlags { auth: string; @@ -59,9 +58,7 @@ export async function pullDatapoints( .map((category) => `${category.category}:${category.name}`) .join(', '), 'Guessed Category': point.pendingCategoryGuesses?.[0] - ? `${point.pendingCategoryGuesses![0]!.category.category}:${ - point.pendingCategoryGuesses![0]!.category.name - }` + ? `${point.pendingCategoryGuesses[0].category.category}:${point.pendingCategoryGuesses[0].category.name}` : '', 'Processing Purposes': point.purposes .map((purpose) => `${purpose.purpose}:${purpose.name}`) @@ -71,18 +68,18 @@ export async function pullDatapoints( point.attributeValues || [], ({ attributeKey }) => attributeKey.name, ), - ).reduce((acc, [key, values]) => { - acc[key] = values.map((value) => value.name).join(','); - return acc; - }, {} as Record), + ).reduce>((accumulator, [key, values]) => { + accumulator[key] = values.map((value) => value.name).join(','); + return accumulator; + }, {}), }; headers = uniq([...headers, ...Object.keys(result)]); return result; }); writeCsv(file, inputs, headers); - } catch (err) { + } catch (error) { logger.error( - colors.red(`An error occurred syncing the datapoints: ${err.message}`), + colors.red(`An error occurred syncing the datapoints: ${error.message}`), ); process.exit(1); } diff --git a/src/commands/inventory/pull-unstructured-discovery-files/impl.ts b/src/commands/inventory/pull-unstructured-discovery-files/impl.ts index 6bc06c37..9c6026f3 100644 --- a/src/commands/inventory/pull-unstructured-discovery-files/impl.ts +++ b/src/commands/inventory/pull-unstructured-discovery-files/impl.ts @@ -1,7 +1,7 @@ -import type { LocalContext } from '../../../context'; import type { UnstructuredSubDataPointRecommendationStatus } from '@transcend-io/privacy-types'; import colors from 'colors'; import { uniq } from 'lodash-es'; +import type { LocalContext } from '../../../context'; import { writeCsv } from '../../../lib/cron'; import { pullUnstructuredSubDataPointRecommendations } from '../../../lib/data-inventory'; import { buildTranscendGraphQLClient } from '../../../lib/graphql'; @@ -65,10 +65,10 @@ export async function pullUnstructuredDiscoveryFiles( return result; }); writeCsv(file, inputs, headers); - } catch (err) { + } catch (error) { logger.error( colors.red( - `An error occurred syncing the unstructured discovery files: ${err.message}`, + `An error occurred syncing the unstructured discovery files: ${error.message}`, ), ); process.exit(1); diff --git a/src/commands/inventory/pull/command.ts b/src/commands/inventory/pull/command.ts index a63f349a..bff74c8a 100644 --- a/src/commands/inventory/pull/command.ts +++ b/src/commands/inventory/pull/command.ts @@ -1,10 +1,10 @@ import { buildCommand, numberParser } from '@stricli/core'; import { ConsentTrackerStatus } from '@transcend-io/privacy-types'; +import { TranscendPullResource } from '../../../enums'; import { createAuthParameter, createTranscendUrlParameter, } from '../../../lib/cli/common-parameters'; -import { TranscendPullResource } from '../../../enums'; export const DEFAULT_TRANSCEND_PULL_RESOURCES = [ TranscendPullResource.DataSilos, diff --git a/src/commands/inventory/pull/impl.ts b/src/commands/inventory/pull/impl.ts index d1796c9c..a6802e91 100644 --- a/src/commands/inventory/pull/impl.ts +++ b/src/commands/inventory/pull/impl.ts @@ -1,24 +1,22 @@ +import fs from 'node:fs'; +import { join } from 'node:path'; import { ConsentTrackerStatus } from '@transcend-io/privacy-types'; +import colors from 'colors'; +import { ADMIN_DASH_INTEGRATIONS } from '../../../constants'; import type { LocalContext } from '../../../context'; import { TranscendPullResource } from '../../../enums'; -import { - DEFAULT_CONSENT_TRACKER_STATUSES, - DEFAULT_TRANSCEND_PULL_RESOURCES, -} from './command'; - -import { logger } from '../../../logger'; -import colors from 'colors'; +import { validateTranscendAuth } from '../../../lib/api-keys'; import { mapSeries } from '../../../lib/bluebird-replace'; -import { join } from 'path'; -import fs from 'fs'; import { buildTranscendGraphQLClient, pullTranscendConfiguration, } from '../../../lib/graphql'; - import { writeTranscendYaml } from '../../../lib/readTranscendYaml'; -import { ADMIN_DASH_INTEGRATIONS } from '../../../constants'; -import { validateTranscendAuth } from '../../../lib/api-keys'; +import { logger } from '../../../logger'; +import { + DEFAULT_CONSENT_TRACKER_STATUSES, + DEFAULT_TRANSCEND_PULL_RESOURCES, +} from './command'; interface PullCommandFlags { auth: string; @@ -79,11 +77,11 @@ export async function pull( logger.info(colors.magenta(`Writing configuration to file "${file}"...`)); writeTranscendYaml(file, configuration); - } catch (err) { + } catch (error) { logger.error( colors.red( `An error occurred syncing the schema: ${ - debug ? err.stack : err.message + debug ? error.stack : error.message }`, ), ); @@ -139,9 +137,11 @@ export async function pull( logger.info( colors.green(`${prefix}Successfully pulled configuration!`), ); - } catch (err) { + } catch (error) { logger.error( - colors.red(`${prefix}Failed to sync configuration. - ${err.message}`), + colors.red( + `${prefix}Failed to sync configuration. - ${error.message}`, + ), ); encounteredErrors.push(apiKey.organizationName); } diff --git a/src/commands/inventory/push/impl.ts b/src/commands/inventory/push/impl.ts index 1904d6da..3ba81b28 100644 --- a/src/commands/inventory/push/impl.ts +++ b/src/commands/inventory/push/impl.ts @@ -1,21 +1,19 @@ +import { existsSync, lstatSync } from 'node:fs'; +import { join } from 'node:path'; +import colors from 'colors'; +import { TranscendInput } from '../../../codecs'; +import { ADMIN_DASH_INTEGRATIONS } from '../../../constants'; import type { LocalContext } from '../../../context'; - -import { logger } from '../../../logger'; +import { listFiles, validateTranscendAuth } from '../../../lib/api-keys'; import { mapSeries } from '../../../lib/bluebird-replace'; -import { existsSync, lstatSync } from 'fs'; -import { join } from 'path'; -import { readTranscendYaml } from '../../../lib/readTranscendYaml'; -import colors from 'colors'; import { buildTranscendGraphQLClient, syncConfigurationToTranscend, } from '../../../lib/graphql'; - -import { ADMIN_DASH_INTEGRATIONS } from '../../../constants'; -import { TranscendInput } from '../../../codecs'; -import { validateTranscendAuth, listFiles } from '../../../lib/api-keys'; -import { mergeTranscendInputs } from '../../../lib/mergeTranscendInputs'; import { parseVariablesFromString } from '../../../lib/helpers/parseVariablesFromString'; +import { mergeTranscendInputs } from '../../../lib/mergeTranscendInputs'; +import { readTranscendYaml } from '../../../lib/readTranscendYaml'; +import { logger } from '../../../logger'; /** * Sync configuration to Transcend @@ -62,10 +60,10 @@ async function syncConfiguration({ }, ); return !encounteredError; - } catch (err) { + } catch (error) { logger.error( colors.red( - `An unexpected error occurred syncing the schema: ${err.message}`, + `An unexpected error occurred syncing the schema: ${error.message}`, ), ); return false; @@ -100,47 +98,45 @@ export async function push( const apiKeyOrList = await validateTranscendAuth(auth); // Parse out the variables - const vars = parseVariablesFromString(variables); + const variables_ = parseVariablesFromString(variables); // check if we are being passed a list of API keys and a list of files let fileList: string[]; - if (Array.isArray(apiKeyOrList) && lstatSync(file).isDirectory()) { - fileList = listFiles(file).map((filePath) => join(file, filePath)); - } else { - fileList = file.split(','); - } + fileList = + Array.isArray(apiKeyOrList) && lstatSync(file).isDirectory() + ? listFiles(file).map((filePath) => join(file, filePath)) + : file.split(','); // Ensure at least one file is parsed - if (fileList.length < 1) { + if (fileList.length === 0) { throw new Error('No file specified!'); } - // eslint-disable-next-line array-callback-return,consistent-return const transcendInputs = fileList.map((filePath) => { // Ensure yaml file exists on disk - if (!existsSync(filePath)) { + if (existsSync(filePath)) { + logger.info(colors.magenta(`Reading file "${filePath}"...`)); + } else { logger.error( colors.red( `The file path does not exist on disk: ${filePath}. You can specify the filepath using --file=./examples/transcend.yml`, ), ); process.exit(1); - } else { - logger.info(colors.magenta(`Reading file "${filePath}"...`)); } try { // Read in the yaml file and validate it's shape - const newContents = readTranscendYaml(filePath, vars); + const newContents = readTranscendYaml(filePath, variables_); logger.info(colors.green(`Successfully read in "${filePath}"`)); return { content: newContents, name: filePath.split('/').pop()!.replace('.yml', ''), }; - } catch (err) { + } catch (error) { logger.error( colors.red( - `The shape of your yaml file is invalid with the following errors: ${err.message}`, + `The shape of your yaml file is invalid with the following errors: ${error.message}`, ), ); process.exit(1); diff --git a/src/commands/inventory/routes.ts b/src/commands/inventory/routes.ts index 39613782..93f500f1 100644 --- a/src/commands/inventory/routes.ts +++ b/src/commands/inventory/routes.ts @@ -1,4 +1,6 @@ import { buildRouteMap } from '@stricli/core'; +import { consentManagerServiceJsonToYmlCommand } from './consent-manager-service-json-to-yml/command'; +import { consentManagersToBusinessEntitiesCommand } from './consent-managers-to-business-entities/command'; import { deriveDataSilosFromDataFlowsCrossInstanceCommand } from './derive-data-silos-from-data-flows-cross-instance/command'; import { deriveDataSilosFromDataFlowsCommand } from './derive-data-silos-from-data-flows/command'; import { discoverSilosCommand } from './discover-silos/command'; @@ -7,8 +9,6 @@ import { pullUnstructuredDiscoveryFilesCommand } from './pull-unstructured-disco import { pullCommand } from './pull/command'; import { pushCommand } from './push/command'; import { scanPackagesCommand } from './scan-packages/command'; -import { consentManagerServiceJsonToYmlCommand } from './consent-manager-service-json-to-yml/command'; -import { consentManagersToBusinessEntitiesCommand } from './consent-managers-to-business-entities/command'; export const inventoryRoutes = buildRouteMap({ routes: { diff --git a/src/commands/inventory/scan-packages/impl.ts b/src/commands/inventory/scan-packages/impl.ts index a8c6c49e..6b6abe12 100644 --- a/src/commands/inventory/scan-packages/impl.ts +++ b/src/commands/inventory/scan-packages/impl.ts @@ -1,13 +1,13 @@ -import type { LocalContext } from '../../../context'; -import { logger } from '../../../logger'; +import { execSync } from 'node:child_process'; import colors from 'colors'; import { ADMIN_DASH } from '../../../constants'; +import type { LocalContext } from '../../../context'; import { findCodePackagesInFolder } from '../../../lib/code-scanning'; import { buildTranscendGraphQLClient, syncCodePackages, } from '../../../lib/graphql'; -import { execSync } from 'child_process'; +import { logger } from '../../../logger'; const REPO_ERROR = 'A repository name must be provided. ' + @@ -41,15 +41,15 @@ export async function scanPackages( ); // Trim and parse the URL const url = name.toString('utf-8').trim(); - [gitRepositoryName] = !url.includes('https:') - ? (url.split(':').pop() || '').split('.') - : url.split('/').slice(3).join('/').split('.'); + [gitRepositoryName] = url.includes('https:') + ? url.split('/').slice(3).join('/').split('.') + : (url.split(':').pop() || '').split('.'); if (!gitRepositoryName) { logger.error(colors.red(REPO_ERROR)); process.exit(1); } - } catch (err) { - logger.error(colors.red(`${REPO_ERROR} - Got error: ${err.message}`)); + } catch (error) { + logger.error(colors.red(`${REPO_ERROR} - Got error: ${error.message}`)); process.exit(1); } } diff --git a/src/commands/migration/sync-ot/command.ts b/src/commands/migration/sync-ot/command.ts index df3fa1eb..0d81fab6 100644 --- a/src/commands/migration/sync-ot/command.ts +++ b/src/commands/migration/sync-ot/command.ts @@ -1,11 +1,11 @@ import { buildCommand, type TypedFlagParameter } from '@stricli/core'; import { ScopeName } from '@transcend-io/privacy-types'; +import type { LocalContext } from '../../../context'; +import { OneTrustPullResource, OneTrustPullSource } from '../../../enums'; import { createAuthParameter, createTranscendUrlParameter, } from '../../../lib/cli/common-parameters'; -import { OneTrustPullResource, OneTrustPullSource } from '../../../enums'; -import type { LocalContext } from '../../../context'; export const syncOtCommand = buildCommand({ loader: async () => { diff --git a/src/commands/migration/sync-ot/impl.ts b/src/commands/migration/sync-ot/impl.ts index d9ef4db3..fd8914f6 100644 --- a/src/commands/migration/sync-ot/impl.ts +++ b/src/commands/migration/sync-ot/impl.ts @@ -1,17 +1,17 @@ -import type { LocalContext } from '../../../context'; -import { logger } from '../../../logger'; import colors from 'colors'; -import { createOneTrustGotInstance } from '../../../lib/oneTrust'; +import type { LocalContext } from '../../../context'; import { OneTrustFileFormat, OneTrustPullResource, OneTrustPullSource, } from '../../../enums'; import { buildTranscendGraphQLClient } from '../../../lib/graphql'; +import { createOneTrustGotInstance } from '../../../lib/oneTrust'; import { syncOneTrustAssessmentsFromFile, syncOneTrustAssessmentsFromOneTrust, } from '../../../lib/oneTrust/helpers'; +import { logger } from '../../../logger'; // Command flag interface interface SyncOtCommandFlags { @@ -44,7 +44,6 @@ export async function syncOt( // Must be able to authenticate to transcend to sync resources to it if (!dryRun && !transcendAuth) { throw new Error( - // eslint-disable-next-line no-template-curly-in-string 'Must specify a "transcendAuth" parameter to sync resources to Transcend. e.g. --transcendAuth=${TRANSCEND_API_KEY}', ); } @@ -131,10 +130,10 @@ export async function syncOt( await syncOneTrustAssessmentsFromFile({ file, transcend }); } } - } catch (err) { + } catch (error) { throw new Error( `An error occurred syncing the resource ${resource} from OneTrust: ${ - debug ? err.stack : err.message + debug ? error.stack : error.message }`, ); } diff --git a/src/commands/request/approve/impl.ts b/src/commands/request/approve/impl.ts index 5c36465c..803cc779 100644 --- a/src/commands/request/approve/impl.ts +++ b/src/commands/request/approve/impl.ts @@ -1,6 +1,5 @@ -import type { LocalContext } from '../../../context'; - import { RequestAction, RequestOrigin } from '@transcend-io/privacy-types'; +import type { LocalContext } from '../../../context'; import { approvePrivacyRequests } from '../../../lib/requests'; interface ApproveCommandFlags { diff --git a/src/commands/request/cancel/impl.ts b/src/commands/request/cancel/impl.ts index c7e9993e..80504a4c 100644 --- a/src/commands/request/cancel/impl.ts +++ b/src/commands/request/cancel/impl.ts @@ -1,5 +1,5 @@ -import type { LocalContext } from '../../../context'; import { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; +import type { LocalContext } from '../../../context'; import { cancelPrivacyRequests } from '../../../lib/requests'; interface CancelCommandFlags { diff --git a/src/commands/request/cron/pull-identifiers/command.ts b/src/commands/request/cron/pull-identifiers/command.ts index ad8a628a..97a6d4f4 100644 --- a/src/commands/request/cron/pull-identifiers/command.ts +++ b/src/commands/request/cron/pull-identifiers/command.ts @@ -1,11 +1,11 @@ import { buildCommand, numberParser } from '@stricli/core'; +import { RequestAction } from '@transcend-io/privacy-types'; import { createAuthParameter, createSombraAuthParameter, createTranscendUrlParameter, } from '../../../../lib/cli/common-parameters'; import { uuidParser } from '../../../../lib/cli/parsers'; -import { RequestAction } from '@transcend-io/privacy-types'; export const pullIdentifiersCommand = buildCommand({ loader: async () => { diff --git a/src/commands/request/cron/pull-identifiers/impl.ts b/src/commands/request/cron/pull-identifiers/impl.ts index 2dc503ae..2f1dd235 100644 --- a/src/commands/request/cron/pull-identifiers/impl.ts +++ b/src/commands/request/cron/pull-identifiers/impl.ts @@ -1,15 +1,14 @@ -import type { LocalContext } from '../../../../context'; +import { RequestAction } from '@transcend-io/privacy-types'; import colors from 'colors'; - -import { logger } from '../../../../logger'; import { uniq } from 'lodash-es'; +import type { LocalContext } from '../../../../context'; import { CsvFormattedIdentifier, parseFilePath, pullChunkedCustomSiloOutstandingIdentifiers, writeCsv, } from '../../../../lib/cron'; -import { RequestAction } from '@transcend-io/privacy-types'; +import { logger } from '../../../../logger'; interface PullIdentifiersCommandFlags { file: string; @@ -69,7 +68,7 @@ export async function pullIdentifiers( ), ); - const headers = uniq(chunk.map((d) => Object.keys(d)).flat()); + const headers = uniq(chunk.flatMap((d) => Object.keys(d))); writeCsv(numberedFileName, chunk, headers); logger.info( colors.green( diff --git a/src/commands/request/cron/pull-profiles/command.ts b/src/commands/request/cron/pull-profiles/command.ts index e20ecfd4..9294f319 100644 --- a/src/commands/request/cron/pull-profiles/command.ts +++ b/src/commands/request/cron/pull-profiles/command.ts @@ -1,11 +1,11 @@ import { buildCommand, numberParser } from '@stricli/core'; +import { RequestAction } from '@transcend-io/privacy-types'; import { createAuthParameter, createSombraAuthParameter, createTranscendUrlParameter, } from '../../../../lib/cli/common-parameters'; import { uuidParser } from '../../../../lib/cli/parsers'; -import { RequestAction } from '@transcend-io/privacy-types'; export const pullProfilesCommand = buildCommand({ loader: async () => { diff --git a/src/commands/request/cron/pull-profiles/impl.ts b/src/commands/request/cron/pull-profiles/impl.ts index 8c7ec0ec..c6ff6848 100644 --- a/src/commands/request/cron/pull-profiles/impl.ts +++ b/src/commands/request/cron/pull-profiles/impl.ts @@ -1,19 +1,19 @@ import type { RequestAction } from '@transcend-io/privacy-types'; -import { logger } from '../../../../logger'; import colors from 'colors'; import { uniq } from 'lodash-es'; -import { map } from '../../../../lib/bluebird-replace'; -import { - buildTranscendGraphQLClient, - fetchRequestFilesForRequest, -} from '../../../../lib/graphql'; import type { LocalContext } from '../../../../context'; +import { map } from '../../../../lib/bluebird-replace'; import { parseFilePath, pullChunkedCustomSiloOutstandingIdentifiers, writeCsv, type CsvFormattedIdentifier, } from '../../../../lib/cron'; +import { + buildTranscendGraphQLClient, + fetchRequestFilesForRequest, +} from '../../../../lib/graphql'; +import { logger } from '../../../../logger'; interface PullProfilesCommandFlags { file: string; @@ -118,7 +118,7 @@ export async function pullProfiles( allTargetIdentifiersCount += results.flat().length; // Write the identifiers and target identifiers to CSV - const headers = uniq(chunk.map((d) => Object.keys(d)).flat()); + const headers = uniq(chunk.flatMap((d) => Object.keys(d))); const numberedFileName = `${baseName}-${fileCount}${extension}`; const numberedFileNameTarget = `${baseNameTarget}-${fileCount}${extensionTarget}`; writeCsv(numberedFileName, chunk, headers); @@ -129,7 +129,7 @@ export async function pullProfiles( ); const targetIdentifiers = results.flat(); - const headers2 = uniq(targetIdentifiers.map((d) => Object.keys(d)).flat()); + const headers2 = uniq(targetIdentifiers.flatMap((d) => Object.keys(d))); writeCsv(numberedFileNameTarget, targetIdentifiers, headers2); logger.info( colors.green( diff --git a/src/commands/request/download-files/impl.ts b/src/commands/request/download-files/impl.ts index 06eceaa2..9828837b 100644 --- a/src/commands/request/download-files/impl.ts +++ b/src/commands/request/download-files/impl.ts @@ -1,6 +1,6 @@ +import { RequestStatus } from '@transcend-io/privacy-types'; import type { LocalContext } from '../../../context'; import { downloadPrivacyRequestFiles } from '../../../lib/requests'; -import { RequestStatus } from '@transcend-io/privacy-types'; interface DownloadFilesCommandFlags { auth: string; diff --git a/src/commands/request/enricher-restart/impl.ts b/src/commands/request/enricher-restart/impl.ts index bef41059..6a28894e 100644 --- a/src/commands/request/enricher-restart/impl.ts +++ b/src/commands/request/enricher-restart/impl.ts @@ -1,9 +1,9 @@ -import type { LocalContext } from '../../../context'; -import { bulkRetryEnrichers } from '../../../lib/requests'; import type { RequestAction, RequestEnricherStatus, } from '@transcend-io/privacy-types'; +import type { LocalContext } from '../../../context'; +import { bulkRetryEnrichers } from '../../../lib/requests'; interface EnricherRestartCommandFlags { auth: string; diff --git a/src/commands/request/export/impl.ts b/src/commands/request/export/impl.ts index 7df4258e..1e538445 100644 --- a/src/commands/request/export/impl.ts +++ b/src/commands/request/export/impl.ts @@ -1,11 +1,10 @@ -import type { LocalContext } from '../../../context'; +import type { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; import colors from 'colors'; - -import { logger } from '../../../logger'; import { uniq } from 'lodash-es'; -import { pullPrivacyRequests } from '../../../lib/requests'; +import type { LocalContext } from '../../../context'; import { writeCsv } from '../../../lib/cron'; -import type { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; +import { pullPrivacyRequests } from '../../../lib/requests'; +import { logger } from '../../../logger'; interface ExportCommandFlags { auth: string; @@ -22,7 +21,7 @@ interface ExportCommandFlags { } // `export` is a reserved keyword, so we need to prefix it with an underscore -// eslint-disable-next-line no-underscore-dangle + export async function _export( this: LocalContext, { @@ -51,9 +50,7 @@ export async function _export( }); // Write to CSV - const headers = uniq( - requestsFormattedForCsv.map((d) => Object.keys(d)).flat(), - ); + const headers = uniq(requestsFormattedForCsv.flatMap((d) => Object.keys(d))); writeCsv(file, requestsFormattedForCsv, headers); logger.info( colors.green( diff --git a/src/commands/request/mark-silent/impl.ts b/src/commands/request/mark-silent/impl.ts index 21ba1bc7..5c4e0840 100644 --- a/src/commands/request/mark-silent/impl.ts +++ b/src/commands/request/mark-silent/impl.ts @@ -1,6 +1,6 @@ +import type { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; import type { LocalContext } from '../../../context'; import { markSilentPrivacyRequests } from '../../../lib/requests'; -import type { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; interface MarkSilentCommandFlags { auth: string; diff --git a/src/commands/request/notify-additional-time/impl.ts b/src/commands/request/notify-additional-time/impl.ts index 1c9e061e..df0ad3f9 100644 --- a/src/commands/request/notify-additional-time/impl.ts +++ b/src/commands/request/notify-additional-time/impl.ts @@ -1,6 +1,6 @@ +import type { RequestAction } from '@transcend-io/privacy-types'; import type { LocalContext } from '../../../context'; import { notifyPrivacyRequestsAdditionalTime } from '../../../lib/requests'; -import type { RequestAction } from '@transcend-io/privacy-types'; interface NotifyAdditionalTimeCommandFlags { auth: string; diff --git a/src/commands/request/preflight/pull-identifiers/impl.ts b/src/commands/request/preflight/pull-identifiers/impl.ts index 62638177..f6a1666f 100644 --- a/src/commands/request/preflight/pull-identifiers/impl.ts +++ b/src/commands/request/preflight/pull-identifiers/impl.ts @@ -1,6 +1,6 @@ +import type { RequestAction } from '@transcend-io/privacy-types'; import type { LocalContext } from '../../../../context'; import { pullManualEnrichmentIdentifiersToCsv } from '../../../../lib/manual-enrichment'; -import type { RequestAction } from '@transcend-io/privacy-types'; interface PullIdentifiersCommandFlags { auth: string; diff --git a/src/commands/request/reject-unverified-identifiers/impl.ts b/src/commands/request/reject-unverified-identifiers/impl.ts index 5b381f87..a49015c8 100644 --- a/src/commands/request/reject-unverified-identifiers/impl.ts +++ b/src/commands/request/reject-unverified-identifiers/impl.ts @@ -1,6 +1,6 @@ +import type { RequestAction } from '@transcend-io/privacy-types'; import type { LocalContext } from '../../../context'; import { removeUnverifiedRequestIdentifiers } from '../../../lib/requests'; -import type { RequestAction } from '@transcend-io/privacy-types'; interface RejectUnverifiedIdentifiersCommandFlags { auth: string; diff --git a/src/commands/request/restart/impl.ts b/src/commands/request/restart/impl.ts index e2e6a665..73a84202 100644 --- a/src/commands/request/restart/impl.ts +++ b/src/commands/request/restart/impl.ts @@ -1,6 +1,6 @@ +import type { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; import type { LocalContext } from '../../../context'; import { bulkRestartRequests } from '../../../lib/requests'; -import type { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; interface RestartCommandFlags { auth: string; diff --git a/src/commands/request/system/mark-request-data-silos-completed/impl.ts b/src/commands/request/system/mark-request-data-silos-completed/impl.ts index b30bcb27..0def94b3 100644 --- a/src/commands/request/system/mark-request-data-silos-completed/impl.ts +++ b/src/commands/request/system/mark-request-data-silos-completed/impl.ts @@ -1,10 +1,9 @@ -import type { LocalContext } from '../../../../context'; import colors from 'colors'; import * as t from 'io-ts'; - -import { logger } from '../../../../logger'; +import type { LocalContext } from '../../../../context'; import { markRequestDataSiloIdsCompleted } from '../../../../lib/cron'; import { readCsv } from '../../../../lib/requests'; +import { logger } from '../../../../logger'; const RequestIdRow = t.type({ 'Request Id': t.string, diff --git a/src/commands/request/system/retry-request-data-silos/impl.ts b/src/commands/request/system/retry-request-data-silos/impl.ts index 80f331a1..ce739e85 100644 --- a/src/commands/request/system/retry-request-data-silos/impl.ts +++ b/src/commands/request/system/retry-request-data-silos/impl.ts @@ -1,5 +1,5 @@ -import type { LocalContext } from '../../../../context'; import type { RequestAction } from '@transcend-io/privacy-types'; +import type { LocalContext } from '../../../../context'; import { retryRequestDataSilos as retryRequestDataSilosHelper } from '../../../../lib/requests'; interface RetryRequestDataSilosCommandFlags { diff --git a/src/commands/request/system/skip-request-data-silos/impl.ts b/src/commands/request/system/skip-request-data-silos/impl.ts index 38a1e0a8..65af084d 100644 --- a/src/commands/request/system/skip-request-data-silos/impl.ts +++ b/src/commands/request/system/skip-request-data-silos/impl.ts @@ -1,5 +1,5 @@ -import type { LocalContext } from '../../../../context'; import type { RequestStatus } from '@transcend-io/privacy-types'; +import type { LocalContext } from '../../../../context'; import { skipRequestDataSilos as skipRequestDataSilosHelper } from '../../../../lib/requests'; interface SkipRequestDataSilosCommandFlags { diff --git a/src/constants.ts b/src/constants.ts index 0c2484b4..dbead72b 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,6 +1,6 @@ import { ScopeName } from '@transcend-io/privacy-types'; -import { TranscendPullResource } from './enums'; import { TranscendInput } from './codecs'; +import { TranscendPullResource } from './enums'; export { description, version } from '../package.json'; export const name = 'transcend'; @@ -27,9 +27,10 @@ export const DEFAULT_TRANSCEND_CONSENT_API = /** * Mapping between resource type and scopes required for cli */ -export const TR_PUSH_RESOURCE_SCOPE_MAP: { - [k in TranscendPullResource]: ScopeName[]; -} = { +export const TR_PUSH_RESOURCE_SCOPE_MAP: Record< + TranscendPullResource, + ScopeName[] +> = { [TranscendPullResource.ApiKeys]: [ScopeName.ViewApiKeys], [TranscendPullResource.Templates]: [ScopeName.ManageEmailTemplates], [TranscendPullResource.DataSilos]: [ @@ -83,9 +84,10 @@ export const TR_PUSH_RESOURCE_SCOPE_MAP: { /** * Mapping between resource type and scopes required for cli */ -export const TR_PULL_RESOURCE_SCOPE_MAP: { - [k in TranscendPullResource]: ScopeName[]; -} = { +export const TR_PULL_RESOURCE_SCOPE_MAP: Record< + TranscendPullResource, + ScopeName[] +> = { [TranscendPullResource.ApiKeys]: [ScopeName.ViewApiKeys], [TranscendPullResource.Templates]: [ScopeName.ViewEmailTemplates], [TranscendPullResource.DataSilos]: [ diff --git a/src/lib/ai/TranscendPromptManager.ts b/src/lib/ai/TranscendPromptManager.ts index 1299199e..86571d25 100644 --- a/src/lib/ai/TranscendPromptManager.ts +++ b/src/lib/ai/TranscendPromptManager.ts @@ -1,58 +1,57 @@ -/* eslint-disable max-lines */ +import type { Handlebars } from '@transcend-io/handlebars-utils'; +import { + createHandlebarsWithHelpers, + HandlebarsInput, +} from '@transcend-io/handlebars-utils'; +import { + ChatCompletionRole, + LargeLanguageModelClient, + PromptRunProductArea, + PromptStatus, + QueueStatus, +} from '@transcend-io/privacy-types'; +import { Secret } from '@transcend-io/secret-value'; import { - Optionalize, - Requirize, apply, decodeCodec, getValues, + Optionalize, + Requirize, } from '@transcend-io/type-utils'; -import type { Handlebars } from '@transcend-io/handlebars-utils'; -import { Secret } from '@transcend-io/secret-value'; +import { GraphQLClient } from 'graphql-request'; import * as t from 'io-ts'; +import { chunk, groupBy, keyBy, uniq } from 'lodash-es'; import { DEFAULT_TRANSCEND_API } from '../../constants'; +import { mapSeries } from '../bluebird-replace'; import { Agent, AgentFile, AgentFileFilterBy, - ReportPromptRunInput, buildTranscendGraphQLClient, fetchAllAgentFiles, fetchAllAgents, reportPromptRun, + ReportPromptRunInput, } from '../graphql'; import { - HandlebarsInput, - createHandlebarsWithHelpers, -} from '@transcend-io/handlebars-utils'; + fetchAllLargeLanguageModels, + LargeLanguageModel, +} from '../graphql/fetchLargeLanguageModels'; import { - TranscendPromptTemplated, - TranscendPromptsAndVariables, fetchPromptsWithVariables, + TranscendPromptsAndVariables, + TranscendPromptTemplated, } from '../graphql/fetchPrompts'; -import { GraphQLClient } from 'graphql-request'; import { - PromptStatus, - ChatCompletionRole, - PromptRunProductArea, - QueueStatus, - LargeLanguageModelClient, -} from '@transcend-io/privacy-types'; -import { - LargeLanguageModel, - fetchAllLargeLanguageModels, -} from '../graphql/fetchLargeLanguageModels'; -import { groupBy, keyBy, uniq, chunk } from 'lodash-es'; -import { mapSeries } from '../bluebird-replace'; -import { - PromptThread, fetchAllPromptThreads, + PromptThread, } from '../graphql/fetchPromptThreads'; /** * An LLM Prompt definition */ export type TranscendPrompt< - TInputParams extends t.Any, + TInputParameters extends t.Any, TOutputCodec extends t.Any, > = ( | { @@ -71,7 +70,7 @@ export type TranscendPrompt< /** The names of the agents that should be loaded along with the prompt */ agentNames?: string[]; /** Codec to validate runtime input shape */ - paramCodec: TInputParams; + paramCodec: TInputParameters; /** Codec to validate output response */ outputCodec: TOutputCodec; /** @@ -109,7 +108,7 @@ export function createRegexForTag(tagName: string): RegExp { */ export function defineTranscendPrompts< TPromptNames extends string, - TPrompts extends { [k in TPromptNames]: TranscendPrompt }, + TPrompts extends Record>, >(prompts: TPrompts): TPrompts { return prompts; } @@ -119,7 +118,7 @@ export function defineTranscendPrompts< */ export type GetPromptParamType< TPromptName extends keyof TPrompts, - TPrompts extends { [k in TPromptName]: TranscendPrompt }, + TPrompts extends Record>, > = t.TypeOf; /** @@ -127,7 +126,7 @@ export type GetPromptParamType< */ export type GetPromptResponseType< TPromptName extends keyof TPrompts, - TPrompts extends { [k in TPromptName]: TranscendPrompt }, + TPrompts extends Record>, > = t.TypeOf; /** @@ -149,11 +148,11 @@ export interface ReportPromptRunOptions }; } -const jsonParseSafe = (obj: string): unknown => { +const jsonParseSafe = (object: string): unknown => { try { - return JSON.parse(obj); - } catch (e) { - return obj; + return JSON.parse(object); + } catch { + return object; } }; @@ -163,7 +162,7 @@ const jsonParseSafe = (obj: string): unknown => { */ export class TranscendPromptManager< TPromptNames extends string, - TPrompts extends { [k in TPromptNames]: TranscendPrompt }, + TPrompts extends Record>, > { /** Prompt definitions */ public prompts: TPrompts; @@ -172,28 +171,28 @@ export class TranscendPromptManager< public handlebarsOptions!: HandlebarsInput; /** Prompt name -> content map, populated by call to Transcend API */ - public promptContentMap?: { [k in TPromptNames]: TranscendPromptTemplated }; + public promptContentMap?: Record; /** The large language models that are registered to this organization for reporting */ public largeLanguageModels: LargeLanguageModel[] = []; /** The agent definitions registered to this organization */ - private agentsByName: { [name in string]: Agent } = {}; + private agentsByName: Record = {}; /** The agent definitions registered to this organization */ - private agentsByAgentId: { [id in string]: Agent } = {}; + private agentsByAgentId: Record = {}; /** The GraphQL client that can be used to call Transcend */ public graphQLClient: GraphQLClient; /** The set of variables to expose in handlebars context specified at class initiation */ - public defaultVariables: { [k in string]: unknown }; + public defaultVariables: Record; /** * The set of variables to expose in handlebars context, * merges defaults with calculated variables from the inventory */ - public variables: { [k in string]: unknown }; + public variables: Record; /** Handlebars compiler */ public handlebars: typeof Handlebars; @@ -245,7 +244,7 @@ export class TranscendPromptManager< /** When true, throw an error if the prompt is not approved */ requireApproval?: boolean; /** The set of variables to expose in handlebars context specified at class initiation */ - defaultVariables?: { [k in string]: unknown }; + defaultVariables?: Record; /** * The cache duration in ms for how long prompts and associated metadata should be cached * When undefined - prompts are cached indefinitely unless explicitly re-requested @@ -278,10 +277,7 @@ export class TranscendPromptManager< */ async fetchPromptsAndMetadata(): Promise { // Determine what to fetch - const promptDefinitions = getValues(this.prompts) as TranscendPrompt< - t.Any, - t.Any - >[]; + const promptDefinitions = getValues(this.prompts); const promptIds = promptDefinitions .map(({ id }) => id) .filter((x): x is string => !!x); @@ -289,7 +285,7 @@ export class TranscendPromptManager< .map(({ title }) => title) .filter((x): x is string => !!x); const agentNames = uniq( - promptDefinitions.map(({ agentNames }) => agentNames || []).flat(), + promptDefinitions.flatMap(({ agentNames }) => agentNames || []), ); // Fetch prompts and data @@ -304,7 +300,7 @@ export class TranscendPromptManager< this.agentsByName = keyBy(agents, 'name'); this.agentsByAgentId = keyBy(agents, 'agentId'); this.largeLanguageModels = largeLanguageModels.filter( - (model) => model.isTranscendHosted === false, + (model) => !model.isTranscendHosted, ); // Lookup prompts by id/title @@ -313,12 +309,11 @@ export class TranscendPromptManager< // Update variables this.variables = { - ...response.calculatedVariables.reduce( - (acc, v) => - Object.assign(acc, { - [v.name]: v.data ? JSON.parse(v.data) : v.data, - }), - {}, + ...Object.fromEntries( + response.calculatedVariables.map((v) => [ + v.name, + v.data ? JSON.parse(v.data) : v.data, + ]), ), ...this.defaultVariables, }; @@ -340,8 +335,8 @@ export class TranscendPromptManager< const result = id ? promptById[id] : title - ? promptByTitle[title] - : undefined; + ? promptByTitle[title] + : undefined; if (!result) { throw new Error( `Failed to find prompt with title: "${title}" and id: "${id}"`, @@ -402,7 +397,7 @@ export class TranscendPromptManager< * @returns The agents that were found matching the names */ async getAgentsByName(names: string[]): Promise { - if (names.length < 1) { + if (names.length === 0) { throw new Error('Expected at least one name to be provided'); } const { hasCache = [], missingCache = [] } = groupBy(names, (name) => @@ -418,10 +413,10 @@ export class TranscendPromptManager< const pageOfAgents = await fetchAllAgents(this.graphQLClient, { names: chunkedName, }); - pageOfAgents.forEach((agent) => { + for (const agent of pageOfAgents) { this.agentsByName[agent.name] = agent; this.agentsByAgentId[agent.agentId] = agent; - }); + } remoteAgents.push(...pageOfAgents); }); return [...cachedAgents, ...remoteAgents]; @@ -509,7 +504,7 @@ export class TranscendPromptManager< */ async compilePrompt( promptName: TPromptName, - params: t.TypeOf, + parameters: t.TypeOf, ): Promise { // Grab the prompt const promptTemplate = await this.getPromptDefinition(promptName); @@ -536,14 +531,14 @@ export class TranscendPromptManager< } // Validate params - decodeCodec(promptInput.paramCodec, params); + decodeCodec(promptInput.paramCodec, parameters); // Compile prompt and template return this.handlebars.compile(promptTemplate.content)({ // template in currentDate by default currentDate: new Date().toISOString(), ...this.variables, - ...params, + ...parameters, }); } @@ -630,8 +625,7 @@ export class TranscendPromptManager< ); } if ( - options.promptRunMessages[options.promptRunMessages.length - 1].role !== - ChatCompletionRole.Assistant + options.promptRunMessages.at(-1).role !== ChatCompletionRole.Assistant ) { throw new Error( `promptRunMessages[${ @@ -639,19 +633,18 @@ export class TranscendPromptManager< }].role is expected to be = ${ChatCompletionRole.Assistant}`, ); } - const response = - options.promptRunMessages[options.promptRunMessages.length - 1].content; + const response = options.promptRunMessages.at(-1).content; let parsed: t.TypeOf; try { // Parse the response parsed = this.parseAiResponse(promptName, response); - } catch (err) { + } catch (error) { await reportPromptRun(this.graphQLClient, { productArea: PromptRunProductArea.PromptManager, ...options, name, - error: err.message, + error: error.message, status: QueueStatus.Error, ...(typeof largeLanguageModel === 'string' ? { largeLanguageModelId: largeLanguageModel } @@ -665,7 +658,7 @@ export class TranscendPromptManager< ...(ind === 0 ? { template: promptInput.content } : {}), })), }); - throw err; + throw error; } // report successful run @@ -768,4 +761,3 @@ export class TranscendPromptManager< }; } } -/* eslint-enable max-lines */ diff --git a/src/lib/ai/filterNullishValuesFromObject.ts b/src/lib/ai/filterNullishValuesFromObject.ts index 3dac2dfa..707ba966 100644 --- a/src/lib/ai/filterNullishValuesFromObject.ts +++ b/src/lib/ai/filterNullishValuesFromObject.ts @@ -7,17 +7,17 @@ import { ObjByString } from '@transcend-io/type-utils'; * @returns Object with null-ish values removed */ export function filterNullishValuesFromObject( - obj: T, + object: T, ): T { - return Object.entries(obj).reduce( - (acc, [k, v]) => + return Object.entries(object).reduce( + (accumulator, [k, v]) => v !== null && v !== undefined && v !== '' && !(Array.isArray(v) && v.length === 0) && !(typeof v === 'object' && Object.keys(v).length === 0) - ? Object.assign(acc, { [k]: v }) - : acc, + ? Object.assign(accumulator, { [k]: v }) + : accumulator, {} as T, ); } diff --git a/src/lib/ai/getGitFilesThatChanged.ts b/src/lib/ai/getGitFilesThatChanged.ts index 1f9da166..7ccd2034 100644 --- a/src/lib/ai/getGitFilesThatChanged.ts +++ b/src/lib/ai/getGitFilesThatChanged.ts @@ -1,6 +1,6 @@ -import { difference } from 'lodash-es'; +import { execSync } from 'node:child_process'; import fastGlob from 'fast-glob'; -import { execSync } from 'child_process'; +import { difference } from 'lodash-es'; /** * Function thats gets the git files that have changed @@ -34,7 +34,7 @@ export function getGitFilesThatChanged({ /** Current commit */ commit: string; /** File diffs */ - fileDiffs: { [k in string]: string }; + fileDiffs: Record; } { // Pull base branch execSync(`git fetch origin ${baseBranch}`); @@ -65,7 +65,7 @@ export function getGitFilesThatChanged({ // Filter out block list const changedFiles = difference( - diff.split('\n').filter((f) => f), + diff.split('\n').filter(Boolean), fileBlockList, ); @@ -76,13 +76,13 @@ export function getGitFilesThatChanged({ : changedFiles; // Get the contents of only the changed files - const fileDiffs: { [k in string]: string } = {}; - filteredChanges.forEach((file) => { + const fileDiffs: Record = {}; + for (const file of filteredChanges) { const contents = execSync(`git show ${latestThisCommit}:${file}`, { encoding: 'utf-8', }); fileDiffs[file] = contents; - }); + } // Pull the github repo name const repoName = githubRepo.split('/').pop()!.split('.')[0]; diff --git a/src/lib/ai/removeLinks.ts b/src/lib/ai/removeLinks.ts index 88fd67f9..83424a77 100644 --- a/src/lib/ai/removeLinks.ts +++ b/src/lib/ai/removeLinks.ts @@ -6,5 +6,5 @@ */ export function removeLinks(inputString: string): string { const regex = /(https?:\/\/[^\s]+)/g; - return inputString.replace(regex, ''); + return inputString.replaceAll(regex, ''); } diff --git a/src/lib/api-keys/generateCrossAccountApiKeys.ts b/src/lib/api-keys/generateCrossAccountApiKeys.ts index 9f1ce407..7a357386 100644 --- a/src/lib/api-keys/generateCrossAccountApiKeys.ts +++ b/src/lib/api-keys/generateCrossAccountApiKeys.ts @@ -1,17 +1,17 @@ +import { ScopeName } from '@transcend-io/privacy-types'; +import colors from 'colors'; +import { StoredApiKey } from '../../codecs'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; +import { logger } from '../../logger'; import { mapSeries } from '../bluebird-replace'; import { + assumeRole, buildTranscendGraphQLClientGeneric, - loginUser, createApiKey, - fetchAllApiKeys, deleteApiKey, - assumeRole, + fetchAllApiKeys, + loginUser, } from '../graphql'; -import { ScopeName } from '@transcend-io/privacy-types'; -import colors from 'colors'; -import { StoredApiKey } from '../../codecs'; -import { logger } from '../../logger'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; export interface ApiKeyGenerateError { /** Name of instance */ @@ -162,16 +162,16 @@ export async function generateCrossAccountApiKeys({ apiKey: '', }); } - } catch (err) { + } catch (error) { logger.error( colors.red( - `Failed to create API key in organization "${role.organization.name}"! - ${err.message}`, + `Failed to create API key in organization "${role.organization.name}"! - ${error.message}`, ), ); errors.push({ organizationName: role.organization.name, organizationId: role.organization.id, - error: err.message, + error: error.message, }); } }); diff --git a/src/lib/api-keys/listDirectories.ts b/src/lib/api-keys/listDirectories.ts index 966ca7a9..fb9a29e0 100644 --- a/src/lib/api-keys/listDirectories.ts +++ b/src/lib/api-keys/listDirectories.ts @@ -1,5 +1,5 @@ -import { readdirSync, statSync } from 'fs'; -import { join } from 'path'; +import { readdirSync, statSync } from 'node:fs'; +import { join } from 'node:path'; /** * List the folders in a directory diff --git a/src/lib/api-keys/listFiles.ts b/src/lib/api-keys/listFiles.ts index fd5e38af..9c696e91 100644 --- a/src/lib/api-keys/listFiles.ts +++ b/src/lib/api-keys/listFiles.ts @@ -1,4 +1,4 @@ -import { existsSync, readdirSync } from 'fs'; +import { existsSync, readdirSync } from 'node:fs'; /** * List the files in a directory @@ -27,7 +27,7 @@ export function listFiles( const files = readdirSync(directory) .filter((fil) => validExtensions - ? validExtensions.filter((ext) => fil.endsWith(ext)).length + ? validExtensions.filter((extension) => fil.endsWith(extension)).length : true, ) .filter((fil) => fil.indexOf('.') > 0); diff --git a/src/lib/api-keys/validateTranscendAuth.ts b/src/lib/api-keys/validateTranscendAuth.ts index e907022e..7d69ba4a 100644 --- a/src/lib/api-keys/validateTranscendAuth.ts +++ b/src/lib/api-keys/validateTranscendAuth.ts @@ -1,9 +1,9 @@ +import { existsSync, readFileSync } from 'node:fs'; import { decodeCodec } from '@transcend-io/type-utils'; import colors from 'colors'; import * as t from 'io-ts'; -import { logger } from '../../logger'; -import { existsSync, readFileSync } from 'fs'; import { StoredApiKey } from '../../codecs'; +import { logger } from '../../logger'; /** * Determine if the `--auth` parameter is an API key or a path to a JSON diff --git a/src/lib/bluebird-replace.ts b/src/lib/bluebird-replace.ts index 0b82e55a..25e44138 100644 --- a/src/lib/bluebird-replace.ts +++ b/src/lib/bluebird-replace.ts @@ -10,8 +10,8 @@ export async function mapSeries( iterator: (item: R, index: number, arrayLength: number) => Promise, ): Promise { const results = []; - for (let i = 0; i < array.length; i += 1) { - results.push(await iterator(array[i], i, array.length)); + for (let index = 0; index < array.length; index += 1) { + results.push(await iterator(array[index], index, array.length)); } return results; } @@ -33,7 +33,7 @@ export async function map( } = {}, ): Promise { const { concurrency = Infinity } = options; - const results: U[] = new Array(array.length); + const results: U[] = Array.from({ length: array.length }); const executing: Promise[] = []; let nextIndex = 0; @@ -56,7 +56,7 @@ export async function map( // Remove the completed promise from executing array const index = executing.indexOf(promise); - if (index > -1) { + if (index !== -1) { executing.splice(index, 1); } }; @@ -64,7 +64,7 @@ export async function map( // Start initial batch of promises up to concurrency limit const initialBatch = Math.min(concurrency, array.length); const initialPromises = []; - for (let i = 0; i < initialBatch; i += 1) { + for (let index = 0; index < initialBatch; index += 1) { initialPromises.push(executeNext()); } diff --git a/src/lib/cli/common-parameters.ts b/src/lib/cli/common-parameters.ts index 45ba8ae5..acafbca8 100644 --- a/src/lib/cli/common-parameters.ts +++ b/src/lib/cli/common-parameters.ts @@ -1,11 +1,11 @@ +import type { TypedFlagParameter } from '@stricli/core'; import { ScopeName, TRANSCEND_SCOPES } from '@transcend-io/privacy-types'; -import { urlParser } from './parsers'; import { DEFAULT_TRANSCEND_API, DEFAULT_TRANSCEND_CONSENT_API, } from '../../constants'; import type { LocalContext } from '../../context'; -import type { TypedFlagParameter } from '@stricli/core'; +import { urlParser } from './parsers'; /** * Common parameter builders for CLI commands diff --git a/src/lib/code-scanning/constants.ts b/src/lib/code-scanning/constants.ts index 5af068a0..889bfc1f 100644 --- a/src/lib/code-scanning/constants.ts +++ b/src/lib/code-scanning/constants.ts @@ -1,22 +1,20 @@ -import { CodeScanningConfig } from './types'; +import { CodePackageType } from '@transcend-io/privacy-types'; import { cocoaPods, + composerJson, + gemfile, gradle, javascriptPackageJson, - gemfile, - composerJson, pubspec, - swift, pythonRequirementsTxt, + swift, } from './integrations'; -import { CodePackageType } from '@transcend-io/privacy-types'; +import { CodeScanningConfig } from './types'; /** * @deprecated TODO: https://transcend.height.app/T-32325 - use code scanning instead */ -export const SILO_DISCOVERY_CONFIGS: { - [k in string]: CodeScanningConfig; -} = { +export const SILO_DISCOVERY_CONFIGS: Record = { cocoaPods, gradle, javascriptPackageJson, @@ -26,9 +24,10 @@ export const SILO_DISCOVERY_CONFIGS: { swift, }; -export const CODE_SCANNING_CONFIGS: { - [k in CodePackageType]: CodeScanningConfig; -} = { +export const CODE_SCANNING_CONFIGS: Record< + CodePackageType, + CodeScanningConfig +> = { [CodePackageType.CocoaPods]: cocoaPods, [CodePackageType.Gradle]: gradle, [CodePackageType.PackageJson]: javascriptPackageJson, diff --git a/src/lib/code-scanning/findCodePackagesInFolder.ts b/src/lib/code-scanning/findCodePackagesInFolder.ts index 903a879b..d4bec9cc 100644 --- a/src/lib/code-scanning/findCodePackagesInFolder.ts +++ b/src/lib/code-scanning/findCodePackagesInFolder.ts @@ -1,9 +1,9 @@ -import fastGlob from 'fast-glob'; +import { getEntries } from '@transcend-io/type-utils'; import colors from 'colors'; +import fastGlob from 'fast-glob'; import { CodePackageInput } from '../../codecs'; -import { getEntries } from '@transcend-io/type-utils'; -import { CODE_SCANNING_CONFIGS } from './constants'; import { logger } from '../../logger'; +import { CODE_SCANNING_CONFIGS } from './constants'; /** * Helper to scan and discovery all of the code packages within a folder @@ -13,7 +13,7 @@ import { logger } from '../../logger'; */ export async function findCodePackagesInFolder({ scanPath, - ignoreDirs = [], + ignoreDirs: ignoreDirectories = [], repositoryName, }: { /** The name of the github repository reporting packages for */ @@ -26,18 +26,21 @@ export async function findCodePackagesInFolder({ const allCodePackages = await Promise.all( getEntries(CODE_SCANNING_CONFIGS).map(async ([codePackageType, config]) => { const { - ignoreDirs: configIgnoreDirs, + ignoreDirs: configIgnoreDirectories, supportedFiles, scanFunction, } = config; - const dirsToIgnore = [...ignoreDirs, ...configIgnoreDirs].filter( - (dir) => dir.length > 0, - ); + const directoriesToIgnore = [ + ...ignoreDirectories, + ...configIgnoreDirectories, + ].filter((dir) => dir.length > 0); try { const filesToScan: string[] = await fastGlob( `${scanPath}/**/${supportedFiles.join('|')}`, { - ignore: dirsToIgnore.map((dir: string) => `${scanPath}/**/${dir}`), + ignore: directoriesToIgnore.map( + (dir: string) => `${scanPath}/**/${dir}`, + ), unique: true, onlyFiles: true, }, @@ -47,29 +50,25 @@ export async function findCodePackagesInFolder({ `Scanning: ${filesToScan.length} files of type ${codePackageType}`, ), ); - const allPackages = filesToScan - .map((filePath) => - scanFunction(filePath).map((result) => ({ - ...result, - relativePath: filePath.replace(`${scanPath}/`, ''), - })), - ) - .flat(); + const allPackages = filesToScan.flatMap((filePath) => + scanFunction(filePath).map((result) => ({ + ...result, + relativePath: filePath.replace(`${scanPath}/`, ''), + })), + ); logger.info( colors.green( `Found: ${allPackages.length} packages and ${ - allPackages - .map( - ({ softwareDevelopmentKits = [] }) => softwareDevelopmentKits, - ) - .flat().length + allPackages.flatMap( + ({ softwareDevelopmentKits = [] }) => softwareDevelopmentKits, + ).length } sdks`, ), ); return allPackages.map( - (pkg): CodePackageInput => ({ - ...pkg, + (package_): CodePackageInput => ({ + ...package_, type: codePackageType, repositoryName, }), diff --git a/src/lib/code-scanning/findFilesToScan.ts b/src/lib/code-scanning/findFilesToScan.ts index 13aaba41..f6535395 100644 --- a/src/lib/code-scanning/findFilesToScan.ts +++ b/src/lib/code-scanning/findFilesToScan.ts @@ -40,25 +40,27 @@ export async function findFilesToScan({ fileGlobs === '' ? supportedFiles : supportedFiles.concat(fileGlobs.split(',')); - const dirsToIgnore = [...ignoreDirs.split(','), ...IGNORE_DIRS].filter( + const directoriesToIgnore = [...ignoreDirs.split(','), ...IGNORE_DIRS].filter( (dir) => dir.length > 0, ); try { const filesToScan: string[] = await fastGlob( `${scanPath}/**/${globsToSupport.join('|')}`, { - ignore: dirsToIgnore.map((dir: string) => `${scanPath}/**/${dir}`), + ignore: directoriesToIgnore.map( + (dir: string) => `${scanPath}/**/${dir}`, + ), unique: true, onlyFiles: true, }, ); logger.info(`Scanning: ${filesToScan.length} files`); - const allPackages = filesToScan - .map((filePath: string) => scanFunction(filePath)) - .flat(); - const allSdks = allPackages - .map((appPackage) => appPackage.softwareDevelopmentKits || []) - .flat(); + const allPackages = filesToScan.flatMap((filePath: string) => + scanFunction(filePath), + ); + const allSdks = allPackages.flatMap( + (appPackage) => appPackage.softwareDevelopmentKits || [], + ); const uniqueDeps = new Set(allSdks.map((sdk) => sdk.name)); const deps = [...uniqueDeps]; logger.info(`Found: ${deps.length} unique dependencies`); diff --git a/src/lib/code-scanning/integrations/cocoaPods.ts b/src/lib/code-scanning/integrations/cocoaPods.ts index c0b774bd..30dfebc5 100644 --- a/src/lib/code-scanning/integrations/cocoaPods.ts +++ b/src/lib/code-scanning/integrations/cocoaPods.ts @@ -1,8 +1,8 @@ -import { readFileSync } from 'fs'; -import { CodeScanningConfig } from '../types'; -import { CodePackageSdk } from '../../../codecs'; -import { findAllWithRegex } from '@transcend-io/type-utils'; +import { readFileSync } from 'node:fs'; import { CodePackageType } from '@transcend-io/privacy-types'; +import { findAllWithRegex } from '@transcend-io/type-utils'; +import { CodePackageSdk } from '../../../codecs'; +import { CodeScanningConfig } from '../types'; const POD_TARGET_REGEX = /target ('|")(.*?)('|")/; const POD_PACKAGE_REGEX = /pod ('|")(.*?)('|")(, ('|")~> (.+?)('|")|)/; @@ -41,13 +41,14 @@ export const cocoaPods: CodeScanningConfig = { type: CodePackageType.CocoaPods, softwareDevelopmentKits: packages .filter( - (pkg) => - pkg.matchIndex > target.matchIndex && - (!targets[ind + 1] || pkg.matchIndex < targets[ind + 1].matchIndex), + (package_) => + package_.matchIndex > target.matchIndex && + (!targets[ind + 1] || + package_.matchIndex < targets[ind + 1].matchIndex), ) - .map((pkg) => ({ - name: pkg.name, - version: pkg.version, + .map((package_) => ({ + name: package_.name, + version: package_.version, })), })); diff --git a/src/lib/code-scanning/integrations/composerJson.ts b/src/lib/code-scanning/integrations/composerJson.ts index 48ab2385..3cf697c5 100644 --- a/src/lib/code-scanning/integrations/composerJson.ts +++ b/src/lib/code-scanning/integrations/composerJson.ts @@ -1,7 +1,7 @@ -import { readFileSync } from 'fs'; -import { CodeScanningConfig } from '../types'; +import { readFileSync } from 'node:fs'; +import { dirname } from 'node:path'; import { CodePackageSdk } from '../../../codecs'; -import { dirname } from 'path'; +import { CodeScanningConfig } from '../types'; export const composerJson: CodeScanningConfig = { supportedFiles: ['composer.json'], @@ -14,7 +14,7 @@ export const composerJson: CodeScanningConfig = { name, description, require: requireDependencies = {}, - 'require-dev': requiredDevDependencies = {}, + 'require-dev': requiredDevelopmentDependencies = {}, } = asJson; return [ { @@ -28,7 +28,7 @@ export const composerJson: CodeScanningConfig = { version: typeof version === 'string' ? version : undefined, }), ), - ...Object.entries(requiredDevDependencies).map( + ...Object.entries(requiredDevelopmentDependencies).map( ([name, version]): CodePackageSdk => ({ name, version: typeof version === 'string' ? version : undefined, diff --git a/src/lib/code-scanning/integrations/gemfile.ts b/src/lib/code-scanning/integrations/gemfile.ts index af7a7be2..28b631df 100644 --- a/src/lib/code-scanning/integrations/gemfile.ts +++ b/src/lib/code-scanning/integrations/gemfile.ts @@ -1,9 +1,9 @@ -import { readFileSync } from 'fs'; -import { CodeScanningConfig } from '../types'; +import { readFileSync } from 'node:fs'; +import { dirname } from 'node:path'; +import { CodePackageType } from '@transcend-io/privacy-types'; import { findAllWithRegex } from '@transcend-io/type-utils'; import { listFiles } from '../../api-keys'; -import { dirname } from 'path'; -import { CodePackageType } from '@transcend-io/privacy-types'; +import { CodeScanningConfig } from '../types'; const GEM_PACKAGE_REGEX = /gem *('|")(.+?)('|")(, *('|")(.+?)('|")|)/; const GEMFILE_PACKAGE_NAME_REGEX = /spec\.name *= *('|")(.+?)('|")/; @@ -54,9 +54,9 @@ export const gemfile: CodeScanningConfig = { name: gemfileName || directory.split('/').pop()!, description: gemfileDescription || undefined, type: CodePackageType.RequirementsTxt, - softwareDevelopmentKits: targets.map((pkg) => ({ - name: pkg.name, - version: pkg.version, + softwareDevelopmentKits: targets.map((package_) => ({ + name: package_.name, + version: package_.version, })), }, ]; diff --git a/src/lib/code-scanning/integrations/gradle.ts b/src/lib/code-scanning/integrations/gradle.ts index 1f36ff4b..70983adf 100644 --- a/src/lib/code-scanning/integrations/gradle.ts +++ b/src/lib/code-scanning/integrations/gradle.ts @@ -1,7 +1,7 @@ -import { readFileSync } from 'fs'; -import { CodeScanningConfig } from '../types'; +import { readFileSync } from 'node:fs'; +import { dirname } from 'node:path'; import { findAllWithRegex } from '@transcend-io/type-utils'; -import { dirname } from 'path'; +import { CodeScanningConfig } from '../types'; const GRADLE_IMPLEMENTATION_REGEX = /implementation( *)('|")(.+?):(.+?):(.+?|)('|")/; diff --git a/src/lib/code-scanning/integrations/javascriptPackageJson.ts b/src/lib/code-scanning/integrations/javascriptPackageJson.ts index 68739429..fe437c32 100644 --- a/src/lib/code-scanning/integrations/javascriptPackageJson.ts +++ b/src/lib/code-scanning/integrations/javascriptPackageJson.ts @@ -1,7 +1,7 @@ -import { readFileSync } from 'fs'; -import { CodeScanningConfig } from '../types'; +import { readFileSync } from 'node:fs'; +import { dirname } from 'node:path'; import { CodePackageSdk } from '../../../codecs'; -import { dirname } from 'path'; +import { CodeScanningConfig } from '../types'; export const javascriptPackageJson: CodeScanningConfig = { supportedFiles: ['package.json'], diff --git a/src/lib/code-scanning/integrations/pubspec.ts b/src/lib/code-scanning/integrations/pubspec.ts index c427601b..0f8e1b72 100644 --- a/src/lib/code-scanning/integrations/pubspec.ts +++ b/src/lib/code-scanning/integrations/pubspec.ts @@ -1,8 +1,8 @@ -import { readFileSync } from 'fs'; -import { CodeScanningConfig } from '../types'; +import { readFileSync } from 'node:fs'; +import { dirname } from 'node:path'; import { CodePackageType } from '@transcend-io/privacy-types'; import yaml from 'js-yaml'; -import { dirname } from 'path'; +import { CodeScanningConfig } from '../types'; /** * Remove YAML comments from a string @@ -16,14 +16,12 @@ function removeYAMLComments(yamlString: string): string { .map((line) => { // Remove inline comments const commentIndex = line.indexOf('#'); - if (commentIndex > -1) { - // Check if '#' is not inside a string - if ( - !line.substring(0, commentIndex).includes('"') && - !line.substring(0, commentIndex).includes("'") - ) { - return line.substring(0, commentIndex).trim(); - } + if ( + commentIndex !== -1 && // Check if '#' is not inside a string + !line.slice(0, Math.max(0, commentIndex)).includes('"') && + !line.slice(0, Math.max(0, commentIndex)).includes("'") + ) { + return line.slice(0, Math.max(0, commentIndex)).trim(); } return line; }) @@ -40,7 +38,7 @@ export const pubspec: CodeScanningConfig = { const { name, description, - dev_dependencies = {}, + dev_dependencies: development_dependencies = {}, dependencies = {}, } = yaml.load(removeYAMLComments(fileContents)) as { /** Name */ @@ -48,9 +46,9 @@ export const pubspec: CodeScanningConfig = { /** Description */ description?: string; /** Dev dependencies */ - dev_dependencies?: { [k in string]: number | Record }; + dev_dependencies?: Record>; /** Dependencies */ - dependencies?: { [k in string]: number | Record }; + dependencies?: Record>; }; return [ { @@ -64,19 +62,21 @@ export const pubspec: CodeScanningConfig = { typeof version === 'string' ? version : typeof version === 'number' - ? version.toString() - : version?.sdk, - })), - ...Object.entries(dev_dependencies).map(([name, version]) => ({ - name, - version: - typeof version === 'string' - ? version - : typeof version === 'number' - ? version.toString() - : version?.sdk, - isDevDependency: true, + ? version.toString() + : version?.sdk, })), + ...Object.entries(development_dependencies).map( + ([name, version]) => ({ + name, + version: + typeof version === 'string' + ? version + : typeof version === 'number' + ? version.toString() + : version?.sdk, + isDevDependency: true, + }), + ), ], }, ]; diff --git a/src/lib/code-scanning/integrations/pythonRequirementsTxt.ts b/src/lib/code-scanning/integrations/pythonRequirementsTxt.ts index 219e5443..fa119fe9 100644 --- a/src/lib/code-scanning/integrations/pythonRequirementsTxt.ts +++ b/src/lib/code-scanning/integrations/pythonRequirementsTxt.ts @@ -1,9 +1,9 @@ -import { readFileSync } from 'fs'; -import { CodeScanningConfig } from '../types'; +import { readFileSync } from 'node:fs'; +import { dirname, join } from 'node:path'; +import { CodePackageType } from '@transcend-io/privacy-types'; import { findAllWithRegex } from '@transcend-io/type-utils'; import { listFiles } from '../../api-keys'; -import { dirname, join } from 'path'; -import { CodePackageType } from '@transcend-io/privacy-types'; +import { CodeScanningConfig } from '../types'; const REQUIREMENTS_PACKAGE_MATCH = /(.+?)(=+)(.+)/; const PACKAGE_NAME = /name *= *('|")(.+?)('|")/; @@ -42,9 +42,9 @@ export const pythonRequirementsTxt: CodeScanningConfig = { name: packageName || directory.split('/').pop()!, description: packageDescription || undefined, type: CodePackageType.RequirementsTxt, - softwareDevelopmentKits: targets.map((pkg) => ({ - name: pkg.name, - version: pkg.version, + softwareDevelopmentKits: targets.map((package_) => ({ + name: package_.name, + version: package_.version, })), }, ]; diff --git a/src/lib/code-scanning/integrations/swift.ts b/src/lib/code-scanning/integrations/swift.ts index 5b864a04..df1f1804 100644 --- a/src/lib/code-scanning/integrations/swift.ts +++ b/src/lib/code-scanning/integrations/swift.ts @@ -1,9 +1,9 @@ -import { readFileSync } from 'fs'; -import { CodeScanningConfig } from '../types'; +import { readFileSync } from 'node:fs'; +import { dirname } from 'node:path'; import { CodePackageType } from '@transcend-io/privacy-types'; import { decodeCodec } from '@transcend-io/type-utils'; import * as t from 'io-ts'; -import { dirname } from 'path'; +import { CodeScanningConfig } from '../types'; const SwiftPackage = t.type({ pins: t.array( diff --git a/src/lib/consent-manager/buildXdiSyncEndpoint.ts b/src/lib/consent-manager/buildXdiSyncEndpoint.ts index 38711fcf..756bcd2d 100644 --- a/src/lib/consent-manager/buildXdiSyncEndpoint.ts +++ b/src/lib/consent-manager/buildXdiSyncEndpoint.ts @@ -1,11 +1,10 @@ import colors from 'colors'; - -import { buildTranscendGraphQLClient, fetchConsentManager } from '../graphql'; import { difference } from 'lodash-es'; -import { map } from '../bluebird-replace'; import { StoredApiKey } from '../../codecs'; import { DEFAULT_TRANSCEND_API } from '../../constants'; import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; +import { buildTranscendGraphQLClient, fetchConsentManager } from '../graphql'; import { domainToHost } from './domainToHost'; /** @@ -20,11 +19,10 @@ import { domainToHost } from './domainToHost'; * ] * } */ -export type XdiSyncGroups = { [k in string]: string[] }; +export type XdiSyncGroups = Record; /** Regular expression for IP addresses - remove these from sync endpoint */ export const IP_ADDRESS_REGEX = - // eslint-disable-next-line max-len /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; /** @@ -87,7 +85,7 @@ export async function buildXdiSyncEndpoint( // construct the sync groups const syncGroups: XdiSyncGroups = {}; - consentManagers.forEach((consentManager) => { + for (const consentManager of consentManagers) { // grab the partition key const partitionKey = // take explicit key first @@ -115,7 +113,7 @@ export async function buildXdiSyncEndpoint( syncGroups[partitionKey] = [ ...new Set([...(syncGroups[partitionKey] || []), ...hosts]), ]; - }); + } // Construct the HTML const syncEndpointHtml = ` diff --git a/src/lib/consent-manager/consentManagersToBusinessEntities.ts b/src/lib/consent-manager/consentManagersToBusinessEntities.ts index 1a12e3c4..76bb356e 100644 --- a/src/lib/consent-manager/consentManagersToBusinessEntities.ts +++ b/src/lib/consent-manager/consentManagersToBusinessEntities.ts @@ -64,13 +64,13 @@ export function consentManagersToBusinessEntities( // Log out info on airgap scripts to host logger.info('\n\n~~~~~~~~~~~\nAirgap scripts to host:'); - businessEntities.forEach(({ attributes, title }, ind) => { + for (const [ind, { attributes, title }] of businessEntities.entries()) { attributes - ?.find((attr) => attr.key === 'Airgap Production URL') + ?.find((attribute) => attribute.key === 'Airgap Production URL') ?.values?.forEach((url) => { logger.info(`${ind}) ${title} - ${url}`); }); - }); + } return businessEntities; } diff --git a/src/lib/consent-manager/createConsentToken.ts b/src/lib/consent-manager/createConsentToken.ts index 9469bccc..22e7e9aa 100644 --- a/src/lib/consent-manager/createConsentToken.ts +++ b/src/lib/consent-manager/createConsentToken.ts @@ -1,4 +1,4 @@ -import * as crypto from 'crypto'; +import * as crypto from 'node:crypto'; import * as jwt from 'jsonwebtoken'; /** diff --git a/src/lib/consent-manager/dataFlowsToDataSilos.ts b/src/lib/consent-manager/dataFlowsToDataSilos.ts index 03da7f98..aa89cc2a 100644 --- a/src/lib/consent-manager/dataFlowsToDataSilos.ts +++ b/src/lib/consent-manager/dataFlowsToDataSilos.ts @@ -1,5 +1,5 @@ -import { DataFlowInput, DataSiloInput } from '../../codecs'; import { union } from 'lodash-es'; +import { DataFlowInput, DataSiloInput } from '../../codecs'; import { IndexedCatalogs } from '../graphql'; /** @@ -32,19 +32,19 @@ export function dataFlowsToDataSilos( const adTechIntegrations: string[] = []; // Mapping from service name to list of - const serviceToFoundOnDomain: { [k in string]: string[] } = {}; + const serviceToFoundOnDomain: Record = {}; // iterate over each flow - inputs.forEach((flow) => { + for (const flow of inputs) { // process data flows with services const { service, attributes = [] } = flow; if (!service || service === 'internalService') { - return; + continue; } // create mapping to found on domain const foundOnDomain = attributes.find( - (attr) => attr.key === 'Found on Domain', + (attribute) => attribute.key === 'Found on Domain', ); // Create a list of all domains where the data flow was found @@ -52,7 +52,7 @@ export function dataFlowsToDataSilos( if (!serviceToFoundOnDomain[service]) { serviceToFoundOnDomain[service] = []; } - serviceToFoundOnDomain[service]!.push( + serviceToFoundOnDomain[service].push( ...foundOnDomain.values.map((v) => v.replace('https://', '').replace('http://', ''), ), @@ -77,7 +77,7 @@ export function dataFlowsToDataSilos( // add to site tech list siteTechIntegrations.push(service); } - }); + } // create the list of ad tech integrations const adTechDataSilos = [...new Set(adTechIntegrations)].map((service) => ({ diff --git a/src/lib/consent-manager/fetchConsentPreferences.ts b/src/lib/consent-manager/fetchConsentPreferences.ts index 5d78a43b..dbecc85f 100644 --- a/src/lib/consent-manager/fetchConsentPreferences.ts +++ b/src/lib/consent-manager/fetchConsentPreferences.ts @@ -1,6 +1,6 @@ -import * as t from 'io-ts'; import { decodeCodec } from '@transcend-io/type-utils'; import type { Got } from 'got'; +import * as t from 'io-ts'; import { ConsentPreferenceFetch } from './types'; export const ConsentPreferenceResponse = t.intersection([ diff --git a/src/lib/consent-manager/updateConsentManagerVersionToLatest.ts b/src/lib/consent-manager/updateConsentManagerVersionToLatest.ts index edeafda0..f846ff00 100644 --- a/src/lib/consent-manager/updateConsentManagerVersionToLatest.ts +++ b/src/lib/consent-manager/updateConsentManagerVersionToLatest.ts @@ -1,15 +1,14 @@ import { ConsentBundleType } from '@transcend-io/privacy-types'; +import colors from 'colors'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; +import { logger } from '../../logger'; import { mapSeries } from '../bluebird-replace'; import { - updateConsentManagerToLatest, buildTranscendGraphQLClient, - fetchConsentManagerId, deployConsentManager, + fetchConsentManagerId, + updateConsentManagerToLatest, } from '../graphql'; -import colors from 'colors'; - -import { logger } from '../../logger'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; /** * Update the consent manager to latest version diff --git a/src/lib/consent-manager/uploadConsents.ts b/src/lib/consent-manager/uploadConsents.ts index 628b2ac9..c682baca 100644 --- a/src/lib/consent-manager/uploadConsents.ts +++ b/src/lib/consent-manager/uploadConsents.ts @@ -1,14 +1,14 @@ -import { createTranscendConsentGotInstance } from '../graphql'; +import { ConsentPreferencesBody } from '@transcend-io/airgap.js-types'; +import { decodeCodec } from '@transcend-io/type-utils'; +import cliProgress from 'cli-progress'; import colors from 'colors'; import * as t from 'io-ts'; import { DEFAULT_TRANSCEND_CONSENT_API } from '../../constants'; +import { logger } from '../../logger'; import { map } from '../bluebird-replace'; +import { createTranscendConsentGotInstance } from '../graphql'; import { createConsentToken } from './createConsentToken'; -import { logger } from '../../logger'; -import cliProgress from 'cli-progress'; -import { decodeCodec } from '@transcend-io/type-utils'; import type { ConsentPreferenceUpload } from './types'; -import { ConsentPreferencesBody } from '@transcend-io/airgap.js-types'; export const USP_STRING_REGEX = /^[0-9][Y|N]([Y|N])[Y|N]$/; @@ -105,7 +105,7 @@ export async function uploadConsents({ ); // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( {}, @@ -144,8 +144,8 @@ export async function uploadConsents({ purposes: purposes ? decodeCodec(PurposeMap, purposes) : consent.usp - ? { SaleOfInfo: saleStatus === 'Y' } - : {}, + ? { SaleOfInfo: saleStatus === 'Y' } + : {}, ...(updated ? { updated: updated === 'true' } : {}), ...(prompted ? { prompted: prompted === 'true' } : {}), ...consent, @@ -159,18 +159,18 @@ export async function uploadConsents({ json: input, }) .json(); - } catch (err) { + } catch (error) { try { - const parsed = JSON.parse(err?.response?.body || '{}'); + const parsed = JSON.parse(error?.response?.body || '{}'); if (parsed.error) { logger.error(colors.red(`Error: ${parsed.error}`)); } - } catch (e) { + } catch { // continue } throw new Error( `Received an error from server: ${ - err?.response?.body || err?.message + error?.response?.body || error?.message }`, ); } @@ -182,7 +182,7 @@ export async function uploadConsents({ ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( diff --git a/src/lib/consent-manager/uploadCookiesFromCsv.ts b/src/lib/consent-manager/uploadCookiesFromCsv.ts index 1b0ef50b..1ef399b2 100644 --- a/src/lib/consent-manager/uploadCookiesFromCsv.ts +++ b/src/lib/consent-manager/uploadCookiesFromCsv.ts @@ -1,13 +1,13 @@ +import { ConsentTrackerStatus } from '@transcend-io/privacy-types'; import colors from 'colors'; +import { CookieCsvInput, CookieInput } from '../../codecs'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; import { logger } from '../../logger'; -import { ConsentTrackerStatus } from '@transcend-io/privacy-types'; import { buildTranscendGraphQLClient, syncCookies } from '../graphql'; -import { readCsv } from '../requests/readCsv'; -import { CookieInput, CookieCsvInput } from '../../codecs'; import { splitCsvToList } from '../requests'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; +import { readCsv } from '../requests/readCsv'; -const OMIT_COLUMNS = [ +const OMIT_COLUMNS = new Set([ 'ID', 'Activity', 'Encounters', @@ -17,7 +17,7 @@ const OMIT_COLUMNS = [ 'Service Description', 'Website URL', 'Categories of Recipients', -]; +]); /** * Upload a set of cookies from CSV @@ -78,7 +78,7 @@ export async function uploadCookiesFromCsv({ attributes: Object.entries(rest) // filter out native columns that are exported from the admin dashboard // but not custom attributes - .filter(([key]) => !OMIT_COLUMNS.includes(key)) + .filter(([key]) => !OMIT_COLUMNS.has(key)) .map(([key, value]) => ({ key, values: splitCsvToList(value), diff --git a/src/lib/consent-manager/uploadDataFlowsFromCsv.ts b/src/lib/consent-manager/uploadDataFlowsFromCsv.ts index fcb18d35..d79817ce 100644 --- a/src/lib/consent-manager/uploadDataFlowsFromCsv.ts +++ b/src/lib/consent-manager/uploadDataFlowsFromCsv.ts @@ -1,13 +1,13 @@ +import { ConsentTrackerStatus } from '@transcend-io/privacy-types'; import colors from 'colors'; +import { DataFlowCsvInput, DataFlowInput } from '../../codecs'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; import { logger } from '../../logger'; -import { ConsentTrackerStatus } from '@transcend-io/privacy-types'; import { buildTranscendGraphQLClient, syncDataFlows } from '../graphql'; -import { readCsv } from '../requests/readCsv'; -import { DataFlowInput, DataFlowCsvInput } from '../../codecs'; import { splitCsvToList } from '../requests'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; +import { readCsv } from '../requests/readCsv'; -const OMIT_COLUMNS = [ +const OMIT_COLUMNS = new Set([ 'ID', 'Activity', 'Encounters', @@ -17,7 +17,7 @@ const OMIT_COLUMNS = [ 'Service Description', 'Website URL', 'Categories of Recipients', -]; +]); /** * Upload a set of data flows from CSV @@ -79,7 +79,7 @@ export async function uploadDataFlowsFromCsv({ attributes: Object.entries(rest) // filter out native columns that are exported from the admin dashboard // but not custom attributes - .filter(([key]) => !OMIT_COLUMNS.includes(key)) + .filter(([key]) => !OMIT_COLUMNS.has(key)) .map(([key, value]) => ({ key, values: splitCsvToList(value), diff --git a/src/lib/cron/markCronIdentifierCompleted.ts b/src/lib/cron/markCronIdentifierCompleted.ts index d73735ce..47b70c9b 100644 --- a/src/lib/cron/markCronIdentifierCompleted.ts +++ b/src/lib/cron/markCronIdentifierCompleted.ts @@ -39,13 +39,15 @@ export async function markCronIdentifierCompleted( }, }); return true; - } catch (err) { + } catch (error) { // handle gracefully - if (err.response?.statusCode === 409) { + if (error.response?.statusCode === 409) { return false; } throw new Error( - `Received an error from server: ${err?.response?.body || err?.message}`, + `Received an error from server: ${ + error?.response?.body || error?.message + }`, ); } } diff --git a/src/lib/cron/markRequestDataSiloIdsCompleted.ts b/src/lib/cron/markRequestDataSiloIdsCompleted.ts index d6b5983c..ff0d03d1 100644 --- a/src/lib/cron/markRequestDataSiloIdsCompleted.ts +++ b/src/lib/cron/markRequestDataSiloIdsCompleted.ts @@ -1,15 +1,15 @@ -import { map } from '../bluebird-replace'; +import { RequestDataSiloStatus } from '@transcend-io/privacy-types'; +import cliProgress from 'cli-progress'; import colors from 'colors'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; import { + buildTranscendGraphQLClient, CHANGE_REQUEST_DATA_SILO_STATUS, fetchRequestDataSilo, makeGraphQLRequest, - buildTranscendGraphQLClient, } from '../graphql'; -import cliProgress from 'cli-progress'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; -import { RequestDataSiloStatus } from '@transcend-io/privacy-types'; /** * Given a CSV of Request IDs, mark associated RequestDataSilos as completed @@ -42,7 +42,7 @@ export async function markRequestDataSiloIdsCompleted({ const client = buildTranscendGraphQLClient(transcendUrl, auth); // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( {}, @@ -74,9 +74,9 @@ export async function markRequestDataSiloIdsCompleted({ requestDataSiloId: requestDataSilo.id, status, }); - } catch (err) { - if (!err.message.includes('Client error: Request must be active:')) { - throw err; + } catch (error) { + if (!error.message.includes('Client error: Request must be active:')) { + throw error; } } @@ -87,7 +87,7 @@ export async function markRequestDataSiloIdsCompleted({ ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( diff --git a/src/lib/cron/pullChunkedCustomSiloOutstandingIdentifiers.ts b/src/lib/cron/pullChunkedCustomSiloOutstandingIdentifiers.ts index 07d9c6b1..607d9134 100644 --- a/src/lib/cron/pullChunkedCustomSiloOutstandingIdentifiers.ts +++ b/src/lib/cron/pullChunkedCustomSiloOutstandingIdentifiers.ts @@ -1,26 +1,26 @@ +import { RequestAction } from '@transcend-io/privacy-types'; +import cliProgress from 'cli-progress'; +import colors from 'colors'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; +import { logger } from '../../logger'; +import { mapSeries } from '../bluebird-replace'; import { buildTranscendGraphQLClient, createSombraGotInstance, fetchRequestDataSiloActiveCount, } from '../graphql'; -import colors from 'colors'; -import cliProgress from 'cli-progress'; import { - pullCronPageOfIdentifiers, CronIdentifier, + pullCronPageOfIdentifiers, } from './pullCronPageOfIdentifiers'; -import { RequestAction } from '@transcend-io/privacy-types'; - -import { logger } from '../../logger'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; -import { mapSeries } from '../bluebird-replace'; /** * A CSV formatted identifier */ -export type CsvFormattedIdentifier = { - [k in string]: string | null | boolean | number; -}; +export type CsvFormattedIdentifier = Record< + string, + string | null | boolean | number +>; export interface CronIdentifierWithAction extends CronIdentifier { /** The request action that the identifier relates to */ @@ -101,7 +101,7 @@ export async function pullChunkedCustomSiloOutstandingIdentifiers({ ); // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( {}, @@ -143,12 +143,8 @@ export async function pullChunkedCustomSiloOutstandingIdentifiers({ const csvFormattedIdentifiers = identifiersWithAction.map( ({ attributes, ...identifier }) => ({ ...identifier, - ...attributes.reduce( - (acc, val) => - Object.assign(acc, { - [val.key]: val.values.join(','), - }), - {}, + ...Object.fromEntries( + attributes.map((value) => [value.key, value.values.join(',')]), ), }), ); @@ -164,14 +160,14 @@ export async function pullChunkedCustomSiloOutstandingIdentifiers({ shouldContinue = pageIdentifiers.length === apiPageSize; offset += apiPageSize; - if (!skipRequestCount) { - progressBar.update(foundRequestIds.size); - } else { + if (skipRequestCount) { logger.info( colors.magenta( `Pulled ${pageIdentifiers.length} outstanding identifiers for ${foundRequestIds.size} requests`, ), ); + } else { + progressBar.update(foundRequestIds.size); } } }); @@ -184,7 +180,7 @@ export async function pullChunkedCustomSiloOutstandingIdentifiers({ if (!skipRequestCount) { progressBar.stop(); } - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( diff --git a/src/lib/cron/pullCronPageOfIdentifiers.ts b/src/lib/cron/pullCronPageOfIdentifiers.ts index b12aff31..a1e7b9f4 100644 --- a/src/lib/cron/pullCronPageOfIdentifiers.ts +++ b/src/lib/cron/pullCronPageOfIdentifiers.ts @@ -1,7 +1,7 @@ -import * as t from 'io-ts'; -import { decodeCodec } from '@transcend-io/type-utils'; import { RequestAction } from '@transcend-io/privacy-types'; +import { decodeCodec } from '@transcend-io/type-utils'; import type { Got } from 'got'; +import * as t from 'io-ts'; export const CronIdentifier = t.type({ /** The identifier value */ @@ -76,9 +76,11 @@ export async function pullCronPageOfIdentifiers( response, ); return items; - } catch (err) { + } catch (error) { throw new Error( - `Received an error from server: ${err?.response?.body || err?.message}`, + `Received an error from server: ${ + error?.response?.body || error?.message + }`, ); } } diff --git a/src/lib/cron/pullCustomSiloOutstandingIdentifiers.ts b/src/lib/cron/pullCustomSiloOutstandingIdentifiers.ts index 10e7cbf4..607d9134 100644 --- a/src/lib/cron/pullCustomSiloOutstandingIdentifiers.ts +++ b/src/lib/cron/pullCustomSiloOutstandingIdentifiers.ts @@ -1,25 +1,26 @@ +import { RequestAction } from '@transcend-io/privacy-types'; +import cliProgress from 'cli-progress'; +import colors from 'colors'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; +import { logger } from '../../logger'; +import { mapSeries } from '../bluebird-replace'; import { buildTranscendGraphQLClient, createSombraGotInstance, fetchRequestDataSiloActiveCount, } from '../graphql'; -import colors from 'colors'; -import cliProgress from 'cli-progress'; import { - pullCronPageOfIdentifiers, CronIdentifier, + pullCronPageOfIdentifiers, } from './pullCronPageOfIdentifiers'; -import { RequestAction } from '@transcend-io/privacy-types'; -import { logger } from '../../logger'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; -import { mapSeries } from '../bluebird-replace'; /** * A CSV formatted identifier */ -export type CsvFormattedIdentifier = { - [k in string]: string | null | boolean | number; -}; +export type CsvFormattedIdentifier = Record< + string, + string | null | boolean | number +>; export interface CronIdentifierWithAction extends CronIdentifier { /** The request action that the identifier relates to */ @@ -100,7 +101,7 @@ export async function pullChunkedCustomSiloOutstandingIdentifiers({ ); // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( {}, @@ -142,12 +143,8 @@ export async function pullChunkedCustomSiloOutstandingIdentifiers({ const csvFormattedIdentifiers = identifiersWithAction.map( ({ attributes, ...identifier }) => ({ ...identifier, - ...attributes.reduce( - (acc, val) => - Object.assign(acc, { - [val.key]: val.values.join(','), - }), - {}, + ...Object.fromEntries( + attributes.map((value) => [value.key, value.values.join(',')]), ), }), ); @@ -163,14 +160,14 @@ export async function pullChunkedCustomSiloOutstandingIdentifiers({ shouldContinue = pageIdentifiers.length === apiPageSize; offset += apiPageSize; - if (!skipRequestCount) { - progressBar.update(foundRequestIds.size); - } else { + if (skipRequestCount) { logger.info( colors.magenta( `Pulled ${pageIdentifiers.length} outstanding identifiers for ${foundRequestIds.size} requests`, ), ); + } else { + progressBar.update(foundRequestIds.size); } } }); @@ -183,7 +180,7 @@ export async function pullChunkedCustomSiloOutstandingIdentifiers({ if (!skipRequestCount) { progressBar.stop(); } - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( diff --git a/src/lib/cron/pushCronIdentifiersFromCsv.ts b/src/lib/cron/pushCronIdentifiersFromCsv.ts index f00a1668..72076830 100644 --- a/src/lib/cron/pushCronIdentifiersFromCsv.ts +++ b/src/lib/cron/pushCronIdentifiersFromCsv.ts @@ -1,15 +1,15 @@ -import { map, mapSeries } from '../bluebird-replace'; +import cliProgress from 'cli-progress'; +import colors from 'colors'; import { chunk } from 'lodash-es'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; +import { logger } from '../../logger'; +import { map, mapSeries } from '../bluebird-replace'; import { createSombraGotInstance } from '../graphql'; -import colors from 'colors'; +import { readCsv } from '../requests'; import { - markCronIdentifierCompleted, CronIdentifierPush, + markCronIdentifierCompleted, } from './markCronIdentifierCompleted'; -import cliProgress from 'cli-progress'; -import { logger } from '../../logger'; -import { readCsv } from '../requests'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; /** * Given a CSV of cron job outputs, mark all requests as completed in Transcend @@ -56,7 +56,7 @@ export async function pushCronIdentifiersFromCsv({ ); // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( {}, @@ -92,10 +92,10 @@ export async function pushCronIdentifiersFromCsv({ } else { failureCount += 1; } - } catch (e) { + } catch (error) { logger.error( colors.red( - `Error notifying Transcend for identifier "${identifier.identifier}" - ${e?.message}`, + `Error notifying Transcend for identifier "${identifier.identifier}" - ${error?.message}`, ), ); errorCount += 1; @@ -119,7 +119,7 @@ export async function pushCronIdentifiersFromCsv({ await mapSeries(chunks, processChunk); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( diff --git a/src/lib/cron/writeCsv.ts b/src/lib/cron/writeCsv.ts index d3c81fe2..f12f8f8c 100644 --- a/src/lib/cron/writeCsv.ts +++ b/src/lib/cron/writeCsv.ts @@ -1,7 +1,6 @@ -import * as fastcsv from 'fast-csv'; -import { createWriteStream, writeFileSync, appendFileSync } from 'fs'; - +import { appendFileSync, createWriteStream, writeFileSync } from 'node:fs'; import { ObjByString } from '@transcend-io/type-utils'; +import * as fastcsv from 'fast-csv'; /** * Escape a CSV value @@ -11,7 +10,7 @@ import { ObjByString } from '@transcend-io/type-utils'; */ function escapeCsvValue(value: string): string { if (value.includes('"') || value.includes(',') || value.includes('\n')) { - return `"${value.replace(/"/g, '""')}"`; + return `"${value.replaceAll('"', '""')}"`; } return value; } @@ -80,9 +79,11 @@ export async function writeCsv( .write(data, { headers, objectMode: true }) .pipe(ws) .on('error', reject) - .on('end', () => resolve(true)); - } catch (err) { - reject(err); + .on('end', () => { + resolve(true); + }); + } catch (error) { + reject(error); } }); } @@ -102,8 +103,11 @@ export function parseFilePath(filePath: string): { const lastDotIndex = filePath.lastIndexOf('.'); return { baseName: - lastDotIndex !== -1 ? filePath.substring(0, lastDotIndex) : filePath, - extension: lastDotIndex !== -1 ? filePath.substring(lastDotIndex) : '.csv', + lastDotIndex === -1 + ? filePath + : filePath.slice(0, Math.max(0, lastDotIndex)), + extension: + lastDotIndex === -1 ? '.csv' : filePath.slice(Math.max(0, lastDotIndex)), }; } @@ -120,7 +124,7 @@ export async function writeLargeCsv( filePath: string, data: ObjByString[], headers: boolean | string[] = true, - chunkSize = 100000, + chunkSize = 100_000, ): Promise { if (data.length <= chunkSize) { // If data is small enough, write to single file @@ -133,13 +137,16 @@ export async function writeLargeCsv( const totalChunks = Math.ceil(data.length / chunkSize); const { baseName, extension } = parseFilePath(filePath); - for (let i = 0; i < totalChunks; i += 1) { - const start = i * chunkSize; + for (let index = 0; index < totalChunks; index += 1) { + const start = index * chunkSize; const end = Math.min(start + chunkSize, data.length); const chunk = data.slice(start, end); // Create filename with chunk number and zero-padding - const chunkNumber = String(i + 1).padStart(String(totalChunks).length, '0'); + const chunkNumber = String(index + 1).padStart( + String(totalChunks).length, + '0', + ); const chunkFilePath = `${baseName}_part${chunkNumber}_of_${totalChunks}${extension}`; await writeCsv(chunkFilePath, chunk, headers); diff --git a/src/lib/data-inventory/pullAllDatapoints.ts b/src/lib/data-inventory/pullAllDatapoints.ts index a1f3f184..9dbbc78d 100644 --- a/src/lib/data-inventory/pullAllDatapoints.ts +++ b/src/lib/data-inventory/pullAllDatapoints.ts @@ -1,23 +1,22 @@ -/* eslint-disable max-lines */ -import { keyBy, uniq, chunk, sortBy } from 'lodash-es'; import { - type DataCategoryType, SubDataPointDataSubCategoryGuessStatus, + type DataCategoryType, } from '@transcend-io/privacy-types'; import cliProgress from 'cli-progress'; -import { gql } from 'graphql-request'; import colors from 'colors'; +import { gql } from 'graphql-request'; import type { GraphQLClient } from 'graphql-request'; +import { chunk, keyBy, sortBy, uniq } from 'lodash-es'; +import type { DataCategoryInput, ProcessingPurposeInput } from '../../codecs'; +import { logger } from '../../logger'; +import { mapSeries } from '../bluebird-replace'; import { - DATAPOINT_EXPORT, DATA_SILO_EXPORT, - type DataSiloAttributeValue, - SUB_DATA_POINTS_COUNT, + DATAPOINT_EXPORT, makeGraphQLRequest, + SUB_DATA_POINTS_COUNT, + type DataSiloAttributeValue, } from '../graphql'; -import { logger } from '../../logger'; -import type { DataCategoryInput, ProcessingPurposeInput } from '../../codecs'; -import { mapSeries } from '../bluebird-replace'; export interface DataSiloCsvPreview { /** ID of dataSilo */ @@ -105,7 +104,7 @@ async function pullSubDatapoints( const subDataPoints: SubDataPointCsvPreview[] = []; // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( @@ -221,24 +220,24 @@ async function pullSubDatapoints( }, ); - cursor = nodes[nodes.length - 1]?.id as string; + cursor = nodes.at(-1)?.id; subDataPoints.push(...nodes); shouldContinue = nodes.length === pageSize; total += nodes.length; offset += nodes.length; progressBar.update(total); - } catch (err) { + } catch (error) { logger.error( colors.red( `An error fetching subdatapoints for cursor ${cursor} and offset ${offset}`, ), ); - throw err; + throw error; } } while (shouldContinue); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; const sorted = sortBy(subDataPoints, 'name'); @@ -275,7 +274,7 @@ async function pullDatapoints( const dataPoints: DataPointCsvPreview[] = []; // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( @@ -314,7 +313,7 @@ async function pullDatapoints( dataPoints.push(...nodes); total += dataPointIdsGroup.length; progressBar.update(total); - } catch (err) { + } catch (error) { logger.error( colors.red( `An error fetching subdatapoints for IDs ${dataPointIdsGroup.join( @@ -322,12 +321,12 @@ async function pullDatapoints( )}`, ), ); - throw err; + throw error; } }); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( @@ -362,7 +361,7 @@ async function pullDataSilos( const dataSilos: DataSiloCsvPreview[] = []; // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( @@ -401,18 +400,18 @@ async function pullDataSilos( dataSilos.push(...nodes); total += dataSiloIdsGroup.length; progressBar.update(total); - } catch (err) { + } catch (error) { logger.error( colors.red( `An error fetching data silos for IDs ${dataSiloIdsGroup.join(', ')}`, ), ); - throw err; + throw error; } }); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( @@ -483,4 +482,3 @@ export async function pullAllDatapoints( dataSilo: dataSiloById[subDataPoint.dataSiloId], })); } -/* eslint-enable max-lines */ diff --git a/src/lib/data-inventory/pullUnstructuredSubDataPointRecommendations.ts b/src/lib/data-inventory/pullUnstructuredSubDataPointRecommendations.ts index 170cf73d..5dbad1b6 100644 --- a/src/lib/data-inventory/pullUnstructuredSubDataPointRecommendations.ts +++ b/src/lib/data-inventory/pullUnstructuredSubDataPointRecommendations.ts @@ -4,8 +4,8 @@ import colors from 'colors'; import { gql, type GraphQLClient } from 'graphql-request'; import { sortBy } from 'lodash-es'; import type { DataCategoryInput } from '../../codecs'; -import { ENTRY_COUNT, makeGraphQLRequest } from '../graphql'; import { logger } from '../../logger'; +import { ENTRY_COUNT, makeGraphQLRequest } from '../graphql'; interface UnstructuredSubDataPointRecommendationCsvPreview { /** ID of subDatapoint */ @@ -74,7 +74,7 @@ export async function pullUnstructuredSubDataPointRecommendations( []; // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( @@ -161,24 +161,24 @@ export async function pullUnstructuredSubDataPointRecommendations( }, ); - cursor = nodes[nodes.length - 1]?.id as string; + cursor = nodes.at(-1)?.id; unstructuredSubDataPointRecommendations.push(...nodes); shouldContinue = nodes.length === pageSize; total += nodes.length; offset += nodes.length; progressBar.update(total); - } catch (err) { + } catch (error) { logger.error( colors.red( `An error fetching subdatapoints for cursor ${cursor} and offset ${offset}`, ), ); - throw err; + throw error; } } while (shouldContinue); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; const sorted = sortBy(unstructuredSubDataPointRecommendations, 'name'); diff --git a/src/lib/graphql/addMessagesToPromptRun.ts b/src/lib/graphql/addMessagesToPromptRun.ts index 81949f1b..bafa002d 100644 --- a/src/lib/graphql/addMessagesToPromptRun.ts +++ b/src/lib/graphql/addMessagesToPromptRun.ts @@ -1,7 +1,7 @@ +import { ChatCompletionRole, QueueStatus } from '@transcend-io/privacy-types'; import { GraphQLClient } from 'graphql-request'; import { ADD_MESSAGES_TO_PROMPT_RUN } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { QueueStatus, ChatCompletionRole } from '@transcend-io/privacy-types'; export interface AddMessagesToPromptRunInput { /** ID of run */ diff --git a/src/lib/graphql/createSombraGotInstance.ts b/src/lib/graphql/createSombraGotInstance.ts index aca717ce..9bd392f0 100644 --- a/src/lib/graphql/createSombraGotInstance.ts +++ b/src/lib/graphql/createSombraGotInstance.ts @@ -1,7 +1,7 @@ import got, { Got } from 'got'; +import { buildTranscendGraphQLClient } from './buildTranscendGraphQLClient'; import { ORGANIZATION } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { buildTranscendGraphQLClient } from './buildTranscendGraphQLClient'; /** * Instantiate an instance of got that is capable of making requests diff --git a/src/lib/graphql/deployConsentManager.ts b/src/lib/graphql/deployConsentManager.ts index 89b96840..008adc2d 100644 --- a/src/lib/graphql/deployConsentManager.ts +++ b/src/lib/graphql/deployConsentManager.ts @@ -1,8 +1,8 @@ import { ConsentBundleType } from '@transcend-io/privacy-types'; import { GraphQLClient } from 'graphql-request'; import { - UPDATE_CONSENT_MANAGER_TO_LATEST, DEPLOY_CONSENT_MANAGER, + UPDATE_CONSENT_MANAGER_TO_LATEST, } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; diff --git a/src/lib/graphql/fetchAllActionItemCollections.ts b/src/lib/graphql/fetchAllActionItemCollections.ts index 66e51783..362c0d33 100644 --- a/src/lib/graphql/fetchAllActionItemCollections.ts +++ b/src/lib/graphql/fetchAllActionItemCollections.ts @@ -1,7 +1,7 @@ +import { TranscendProduct } from '@transcend-io/privacy-types'; import { GraphQLClient } from 'graphql-request'; import { GLOBAL_ACTION_ITEM_COLLECTIONS } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { TranscendProduct } from '@transcend-io/privacy-types'; export interface ActionItemCollection { /** ID of collection */ diff --git a/src/lib/graphql/fetchAllActionItems.ts b/src/lib/graphql/fetchAllActionItems.ts index 69a05771..cd6c409d 100644 --- a/src/lib/graphql/fetchAllActionItems.ts +++ b/src/lib/graphql/fetchAllActionItems.ts @@ -1,10 +1,10 @@ -import { GraphQLClient } from 'graphql-request'; -import { GLOBAL_ACTION_ITEMS } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; import { ActionItemCode, ActionItemPriorityOverride, } from '@transcend-io/privacy-types'; +import { GraphQLClient } from 'graphql-request'; +import { GLOBAL_ACTION_ITEMS } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface ActionItemRaw { /** ID of action item */ diff --git a/src/lib/graphql/fetchAllActions.ts b/src/lib/graphql/fetchAllActions.ts index 22520264..fb4fb13c 100644 --- a/src/lib/graphql/fetchAllActions.ts +++ b/src/lib/graphql/fetchAllActions.ts @@ -1,10 +1,10 @@ -import { GraphQLClient } from 'graphql-request'; import { IsoCountryCode, IsoCountrySubdivisionCode, RegionDetectionMethod, RequestAction, } from '@transcend-io/privacy-types'; +import { GraphQLClient } from 'graphql-request'; import { ACTIONS } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; diff --git a/src/lib/graphql/fetchAllAgentFiles.ts b/src/lib/graphql/fetchAllAgentFiles.ts index 3ed47256..27813b64 100644 --- a/src/lib/graphql/fetchAllAgentFiles.ts +++ b/src/lib/graphql/fetchAllAgentFiles.ts @@ -1,7 +1,7 @@ +import { PromptFilePurpose } from '@transcend-io/privacy-types'; import { GraphQLClient } from 'graphql-request'; import { AGENT_FILES } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { PromptFilePurpose } from '@transcend-io/privacy-types'; export interface AgentFile { /** ID of agentFile */ diff --git a/src/lib/graphql/fetchAllAgentFunctions.ts b/src/lib/graphql/fetchAllAgentFunctions.ts index fedecc62..2f0ba406 100644 --- a/src/lib/graphql/fetchAllAgentFunctions.ts +++ b/src/lib/graphql/fetchAllAgentFunctions.ts @@ -1,7 +1,7 @@ import { GraphQLClient } from 'graphql-request'; +import type { JSONSchema7 } from 'json-schema'; import { AGENT_FUNCTIONS } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import type { JSONSchema7 } from 'json-schema'; export interface AgentFunction { /** ID of agentFunction */ diff --git a/src/lib/graphql/fetchAllAgents.ts b/src/lib/graphql/fetchAllAgents.ts index 939cac34..8f59af03 100644 --- a/src/lib/graphql/fetchAllAgents.ts +++ b/src/lib/graphql/fetchAllAgents.ts @@ -1,7 +1,7 @@ +import { LargeLanguageModelClient } from '@transcend-io/privacy-types'; import { GraphQLClient } from 'graphql-request'; import { AGENTS } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { LargeLanguageModelClient } from '@transcend-io/privacy-types'; export interface Agent { /** ID of agent */ diff --git a/src/lib/graphql/fetchAllAssessmentTemplates.ts b/src/lib/graphql/fetchAllAssessmentTemplates.ts index 28d8c3c7..3af4853e 100644 --- a/src/lib/graphql/fetchAllAssessmentTemplates.ts +++ b/src/lib/graphql/fetchAllAssessmentTemplates.ts @@ -1,15 +1,15 @@ +import { + AssessmentFormTemplateSource, + AssessmentFormTemplateStatus, +} from '@transcend-io/privacy-types'; import { GraphQLClient } from 'graphql-request'; -import { ASSESSMENT_TEMPLATES } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; import type { AssessmentSection, RetentionSchedule, UserPreview, } from './fetchAllAssessments'; -import { - AssessmentFormTemplateSource, - AssessmentFormTemplateStatus, -} from '@transcend-io/privacy-types'; +import { ASSESSMENT_TEMPLATES } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; /** * Represents an assessment template with various properties and metadata. diff --git a/src/lib/graphql/fetchAllAssessments.ts b/src/lib/graphql/fetchAllAssessments.ts index 910df076..19319714 100644 --- a/src/lib/graphql/fetchAllAssessments.ts +++ b/src/lib/graphql/fetchAllAssessments.ts @@ -1,7 +1,3 @@ -/* eslint-disable max-lines */ -import { GraphQLClient } from 'graphql-request'; -import { ASSESSMENTS } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; import { AssessmentFormStatus, AssessmentQuestionSubType, @@ -14,6 +10,9 @@ import { RetentionScheduleOperation, RetentionScheduleType, } from '@transcend-io/privacy-types'; +import { GraphQLClient } from 'graphql-request'; +import { ASSESSMENTS } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; /** * Represents an assessment with various properties and metadata. @@ -367,4 +366,3 @@ export async function fetchAllAssessments( return assessments.sort((a, b) => a.title.localeCompare(b.title)); } -/* eslint-enable max-lines */ diff --git a/src/lib/graphql/fetchAllAttributes.ts b/src/lib/graphql/fetchAllAttributes.ts index dd1f4ef8..9d8c49f6 100644 --- a/src/lib/graphql/fetchAllAttributes.ts +++ b/src/lib/graphql/fetchAllAttributes.ts @@ -1,12 +1,11 @@ -import { GraphQLClient } from 'graphql-request'; -import { ATTRIBUTES, ATTRIBUTE_VALUES } from './gqls'; - -import { logger } from '../../logger'; -import colors from 'colors'; import { AttributeKeyType, AttributeSupportedResourceType, } from '@transcend-io/privacy-types'; +import colors from 'colors'; +import { GraphQLClient } from 'graphql-request'; +import { logger } from '../../logger'; +import { ATTRIBUTE_VALUES, ATTRIBUTES } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface AttributeValue { diff --git a/src/lib/graphql/fetchAllBusinessEntities.ts b/src/lib/graphql/fetchAllBusinessEntities.ts index 8605212b..1a87f99a 100644 --- a/src/lib/graphql/fetchAllBusinessEntities.ts +++ b/src/lib/graphql/fetchAllBusinessEntities.ts @@ -1,10 +1,10 @@ -import { GraphQLClient } from 'graphql-request'; -import { BUSINESS_ENTITIES } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; import { IsoCountryCode, IsoCountrySubdivisionCode, } from '@transcend-io/privacy-types'; +import { GraphQLClient } from 'graphql-request'; +import { BUSINESS_ENTITIES } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface BusinessEntity { /** ID of business entity */ diff --git a/src/lib/graphql/fetchAllCodePackages.ts b/src/lib/graphql/fetchAllCodePackages.ts index 49fd3d3e..5360c50a 100644 --- a/src/lib/graphql/fetchAllCodePackages.ts +++ b/src/lib/graphql/fetchAllCodePackages.ts @@ -1,7 +1,7 @@ +import { CodePackageType } from '@transcend-io/privacy-types'; import { GraphQLClient } from 'graphql-request'; import { CODE_PACKAGES } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { CodePackageType } from '@transcend-io/privacy-types'; export interface CodePackage { /** ID of code package */ diff --git a/src/lib/graphql/fetchAllCookies.ts b/src/lib/graphql/fetchAllCookies.ts index f5b9d0ed..ced750ec 100644 --- a/src/lib/graphql/fetchAllCookies.ts +++ b/src/lib/graphql/fetchAllCookies.ts @@ -1,11 +1,11 @@ -import { GraphQLClient } from 'graphql-request'; -import { COOKIES } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { fetchConsentManagerId } from './fetchConsentManagerId'; import { ConsentTrackerSource, ConsentTrackerStatus, } from '@transcend-io/privacy-types'; +import { GraphQLClient } from 'graphql-request'; +import { fetchConsentManagerId } from './fetchConsentManagerId'; +import { COOKIES } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface Cookie { /** ID of the cookie */ diff --git a/src/lib/graphql/fetchAllDataCategories.ts b/src/lib/graphql/fetchAllDataCategories.ts index 027a6cdb..f01c386d 100644 --- a/src/lib/graphql/fetchAllDataCategories.ts +++ b/src/lib/graphql/fetchAllDataCategories.ts @@ -1,7 +1,7 @@ +import { DataCategoryType } from '@transcend-io/privacy-types'; import { GraphQLClient } from 'graphql-request'; import { DATA_SUB_CATEGORIES } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { DataCategoryType } from '@transcend-io/privacy-types'; export interface DataSubCategory { /** ID of data category */ diff --git a/src/lib/graphql/fetchAllDataFlows.ts b/src/lib/graphql/fetchAllDataFlows.ts index f78176b1..04dfd505 100644 --- a/src/lib/graphql/fetchAllDataFlows.ts +++ b/src/lib/graphql/fetchAllDataFlows.ts @@ -1,12 +1,12 @@ -import { GraphQLClient } from 'graphql-request'; -import { DATA_FLOWS } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { fetchConsentManagerId } from './fetchConsentManagerId'; import { - DataFlowScope, ConsentTrackerSource, ConsentTrackerStatus, + DataFlowScope, } from '@transcend-io/privacy-types'; +import { GraphQLClient } from 'graphql-request'; +import { fetchConsentManagerId } from './fetchConsentManagerId'; +import { DATA_FLOWS } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface DataFlow { /** ID of data flow */ diff --git a/src/lib/graphql/fetchAllMessages.ts b/src/lib/graphql/fetchAllMessages.ts index 2451d55f..da94a991 100644 --- a/src/lib/graphql/fetchAllMessages.ts +++ b/src/lib/graphql/fetchAllMessages.ts @@ -1,7 +1,7 @@ +import { LanguageKey } from '@transcend-io/internationalization'; import { GraphQLClient } from 'graphql-request'; import { MESSAGES } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { LanguageKey } from '@transcend-io/internationalization'; export interface Message { /** ID of message */ diff --git a/src/lib/graphql/fetchAllPolicies.ts b/src/lib/graphql/fetchAllPolicies.ts index 831d4fa5..88095351 100644 --- a/src/lib/graphql/fetchAllPolicies.ts +++ b/src/lib/graphql/fetchAllPolicies.ts @@ -1,8 +1,8 @@ +import { LanguageKey } from '@transcend-io/internationalization'; import { GraphQLClient } from 'graphql-request'; +import { fetchPrivacyCenterUrl } from './fetchPrivacyCenterId'; import { POLICIES } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { LanguageKey } from '@transcend-io/internationalization'; -import { fetchPrivacyCenterUrl } from './fetchPrivacyCenterId'; export interface Policy { /** ID of policy */ diff --git a/src/lib/graphql/fetchAllPreferenceTopics.ts b/src/lib/graphql/fetchAllPreferenceTopics.ts index 25ab1380..710a81eb 100644 --- a/src/lib/graphql/fetchAllPreferenceTopics.ts +++ b/src/lib/graphql/fetchAllPreferenceTopics.ts @@ -1,7 +1,7 @@ +import { PreferenceTopicType } from '@transcend-io/privacy-types'; import { GraphQLClient } from 'graphql-request'; import { PREFERENCE_TOPICS } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { PreferenceTopicType } from '@transcend-io/privacy-types'; export interface PreferenceTopic { /** ID of preference topic */ diff --git a/src/lib/graphql/fetchAllPrivacyCenters.ts b/src/lib/graphql/fetchAllPrivacyCenters.ts index a1837d70..e36d7696 100644 --- a/src/lib/graphql/fetchAllPrivacyCenters.ts +++ b/src/lib/graphql/fetchAllPrivacyCenters.ts @@ -1,9 +1,9 @@ -import { GraphQLClient } from 'graphql-request'; -import { PRIVACY_CENTER } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; import { LanguageKey } from '@transcend-io/internationalization'; import { PrivacyCenterThemePartial } from '@transcend-io/privacy-types'; +import { GraphQLClient } from 'graphql-request'; import { fetchPrivacyCenterUrl } from './fetchPrivacyCenterId'; +import { PRIVACY_CENTER } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface PrivacyCenter { /** ID of the privacy center */ diff --git a/src/lib/graphql/fetchAllProcessingPurposes.ts b/src/lib/graphql/fetchAllProcessingPurposes.ts index e6387ecc..4f1c8cd4 100644 --- a/src/lib/graphql/fetchAllProcessingPurposes.ts +++ b/src/lib/graphql/fetchAllProcessingPurposes.ts @@ -1,7 +1,7 @@ +import { ProcessingPurpose } from '@transcend-io/privacy-types'; import { GraphQLClient } from 'graphql-request'; import { PROCESSING_PURPOSE_SUB_CATEGORIES } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { ProcessingPurpose } from '@transcend-io/privacy-types'; export interface ProcessingPurposeSubCategory { /** ID of processing purpose */ diff --git a/src/lib/graphql/fetchAllPurposes.ts b/src/lib/graphql/fetchAllPurposes.ts index 43e8b13d..de3e548b 100644 --- a/src/lib/graphql/fetchAllPurposes.ts +++ b/src/lib/graphql/fetchAllPurposes.ts @@ -1,11 +1,11 @@ -import { GraphQLClient } from 'graphql-request'; -import { PURPOSES } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; +import { UserPrivacySignalEnum } from '@transcend-io/airgap.js-types'; import { DefaultConsentOption, PreferenceStoreAuthLevel, } from '@transcend-io/privacy-types'; -import { UserPrivacySignalEnum } from '@transcend-io/airgap.js-types'; +import { GraphQLClient } from 'graphql-request'; +import { PURPOSES } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface Purpose { /** ID of purpose */ diff --git a/src/lib/graphql/fetchAllPurposesAndPreferences.ts b/src/lib/graphql/fetchAllPurposesAndPreferences.ts index 757a8d8b..a0e9ad39 100644 --- a/src/lib/graphql/fetchAllPurposesAndPreferences.ts +++ b/src/lib/graphql/fetchAllPurposesAndPreferences.ts @@ -1,9 +1,9 @@ import { GraphQLClient } from 'graphql-request'; -import { Purpose, fetchAllPurposes } from './fetchAllPurposes'; import { - PreferenceTopic, fetchAllPreferenceTopics, + PreferenceTopic, } from './fetchAllPreferenceTopics'; +import { fetchAllPurposes, Purpose } from './fetchAllPurposes'; export interface PurposeWithPreferences extends Purpose { /** Topics */ diff --git a/src/lib/graphql/fetchAllRequestEnrichers.ts b/src/lib/graphql/fetchAllRequestEnrichers.ts index 7b64d124..98970f78 100644 --- a/src/lib/graphql/fetchAllRequestEnrichers.ts +++ b/src/lib/graphql/fetchAllRequestEnrichers.ts @@ -1,5 +1,5 @@ -import { GraphQLClient } from 'graphql-request'; import { RequestEnricherStatus } from '@transcend-io/privacy-types'; +import { GraphQLClient } from 'graphql-request'; import { REQUEST_ENRICHERS } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; diff --git a/src/lib/graphql/fetchAllRequestIdentifiers.ts b/src/lib/graphql/fetchAllRequestIdentifiers.ts index 6dab2d67..d81ff2c8 100644 --- a/src/lib/graphql/fetchAllRequestIdentifiers.ts +++ b/src/lib/graphql/fetchAllRequestIdentifiers.ts @@ -4,7 +4,6 @@ import type { Got } from 'got'; import { GraphQLClient } from 'graphql-request'; import * as t from 'io-ts'; import semver from 'semver'; - import { SOMBRA_VERSION } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; @@ -66,7 +65,7 @@ export async function fetchAllRequestIdentifiers( version: string; }; }; - }>(client!, SOMBRA_VERSION); + }>(client, SOMBRA_VERSION); if (version && semver.lt(version, MIN_SOMBRA_VERSION_TO_DECRYPT)) { throw new Error( @@ -77,7 +76,7 @@ export async function fetchAllRequestIdentifiers( do { let response: unknown; try { - response = await sombra! + response = await sombra .post<{ /** Decrypted identifiers */ identifiers: RequestIdentifier[]; @@ -89,10 +88,10 @@ export async function fetchAllRequestIdentifiers( }, }) .json(); - } catch (err) { + } catch (error) { throw new Error( `Failed to fetch request identifiers: ${ - err?.response?.body || err?.message + error?.response?.body || error?.message }`, ); } diff --git a/src/lib/graphql/fetchAllRequests.ts b/src/lib/graphql/fetchAllRequests.ts index 81b8615b..44ac99dc 100644 --- a/src/lib/graphql/fetchAllRequests.ts +++ b/src/lib/graphql/fetchAllRequests.ts @@ -1,19 +1,19 @@ -import { GraphQLClient } from 'graphql-request'; -import colors from 'colors'; -import { REQUESTS } from './gqls'; -import * as t from 'io-ts'; -import cliProgress from 'cli-progress'; -import { valuesOf } from '@transcend-io/type-utils'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; +import { LanguageKey } from '@transcend-io/internationalization'; import { + IsoCountryCode, + IsoCountrySubdivisionCode, RequestAction, RequestOrigin, RequestStatus, - IsoCountryCode, - IsoCountrySubdivisionCode, } from '@transcend-io/privacy-types'; +import { valuesOf } from '@transcend-io/type-utils'; +import cliProgress from 'cli-progress'; +import colors from 'colors'; +import { GraphQLClient } from 'graphql-request'; +import * as t from 'io-ts'; import { logger } from '../../logger'; -import { LanguageKey } from '@transcend-io/internationalization'; +import { REQUESTS } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; export const PrivacyRequest = t.intersection([ t.type({ @@ -116,7 +116,7 @@ export async function fetchAllRequests( logger.info(colors.magenta('Fetching requests...')); // create a new progress bar instance and use shades_classic theme - const t0 = new Date().getTime(); + const t0 = Date.now(); const progressBar = new cliProgress.SingleBar( {}, cliProgress.Presets.shades_classic, @@ -170,7 +170,7 @@ export async function fetchAllRequests( } while (shouldContinue); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; // Log completion time diff --git a/src/lib/graphql/fetchAllSoftwareDevelopmentKits.ts b/src/lib/graphql/fetchAllSoftwareDevelopmentKits.ts index 4dbbf32b..eb73dc90 100644 --- a/src/lib/graphql/fetchAllSoftwareDevelopmentKits.ts +++ b/src/lib/graphql/fetchAllSoftwareDevelopmentKits.ts @@ -1,7 +1,7 @@ +import { CodePackageType } from '@transcend-io/privacy-types'; import { GraphQLClient } from 'graphql-request'; import { SOFTWARE_DEVELOPMENT_KITS } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { CodePackageType } from '@transcend-io/privacy-types'; export interface SoftwareDevelopmentKit { /** ID of software development kit */ diff --git a/src/lib/graphql/fetchAllTeams.ts b/src/lib/graphql/fetchAllTeams.ts index 527c94d6..2acaafcb 100644 --- a/src/lib/graphql/fetchAllTeams.ts +++ b/src/lib/graphql/fetchAllTeams.ts @@ -1,7 +1,7 @@ +import { ScopeName } from '@transcend-io/privacy-types'; import { GraphQLClient } from 'graphql-request'; import { TEAMS } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { ScopeName } from '@transcend-io/privacy-types'; export interface Team { /** ID of team */ diff --git a/src/lib/graphql/fetchAllVendors.ts b/src/lib/graphql/fetchAllVendors.ts index 798daed4..08fe77b7 100644 --- a/src/lib/graphql/fetchAllVendors.ts +++ b/src/lib/graphql/fetchAllVendors.ts @@ -1,10 +1,10 @@ -import { GraphQLClient } from 'graphql-request'; -import { VENDORS } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; import { IsoCountryCode, IsoCountrySubdivisionCode, } from '@transcend-io/privacy-types'; +import { GraphQLClient } from 'graphql-request'; +import { VENDORS } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface Vendor { /** ID of vendor */ diff --git a/src/lib/graphql/fetchApiKeys.ts b/src/lib/graphql/fetchApiKeys.ts index fb8ffefa..64cdb963 100644 --- a/src/lib/graphql/fetchApiKeys.ts +++ b/src/lib/graphql/fetchApiKeys.ts @@ -1,9 +1,9 @@ -import { GraphQLClient } from 'graphql-request'; -import { API_KEYS } from './gqls'; -import { keyBy, uniq, difference } from 'lodash-es'; -import { logger } from '../../logger'; import colors from 'colors'; +import { GraphQLClient } from 'graphql-request'; +import { difference, keyBy, uniq } from 'lodash-es'; import { TranscendInput } from '../../codecs'; +import { logger } from '../../logger'; +import { API_KEYS } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface ApiKey { @@ -70,7 +70,7 @@ export async function fetchApiKeys( }: TranscendInput, client: GraphQLClient, fetchAll = false, -): Promise<{ [k in string]: ApiKey }> { +): Promise> { logger.info( colors.magenta( `Fetching ${fetchAll ? 'all' : apiKeyInputs.length} API keys...`, diff --git a/src/lib/graphql/fetchCatalogs.ts b/src/lib/graphql/fetchCatalogs.ts index d8a9ff06..75502a95 100644 --- a/src/lib/graphql/fetchCatalogs.ts +++ b/src/lib/graphql/fetchCatalogs.ts @@ -51,9 +51,9 @@ export async function fetchAllCatalogs( export interface IndexedCatalogs { /** Mapping from service name to service title */ - serviceToTitle: { [k in string]: string }; + serviceToTitle: Record; /** Mapping from service name to boolean indicate if service has API integration support */ - serviceToSupportedIntegration: { [k in string]: boolean }; + serviceToSupportedIntegration: Record; } /** @@ -72,19 +72,19 @@ export async function fetchAndIndexCatalogs(client: GraphQLClient): Promise< const catalogs = await fetchAllCatalogs(client); // Create mapping from service name to service title - const serviceToTitle = catalogs.reduce( - (acc, catalog) => - Object.assign(acc, { [catalog.integrationName]: catalog.title }), - {} as { [k in string]: string }, + const serviceToTitle = Object.fromEntries( + catalogs.map>((catalog) => [ + catalog.integrationName, + catalog.title, + ]), ); // Create mapping from service name to boolean indicate if service has API integration support - const serviceToSupportedIntegration = catalogs.reduce( - (acc, catalog) => - Object.assign(acc, { - [catalog.integrationName]: catalog.hasApiFunctionality, - }), - {} as { [k in string]: boolean }, + const serviceToSupportedIntegration = Object.fromEntries( + catalogs.map>((catalog) => [ + catalog.integrationName, + catalog.hasApiFunctionality, + ]), ); return { diff --git a/src/lib/graphql/fetchConsentManagerId.ts b/src/lib/graphql/fetchConsentManagerId.ts index f6ea9934..e8a7d4ca 100644 --- a/src/lib/graphql/fetchConsentManagerId.ts +++ b/src/lib/graphql/fetchConsentManagerId.ts @@ -1,25 +1,25 @@ -import { GraphQLClient } from 'graphql-request'; import { + BrowserLanguage, + InitialViewState, + OnConsentExpiry, +} from '@transcend-io/airgap.js-types'; +import { + BrowserTimeZone, ConsentPrecedenceOption, - UnknownRequestPolicy, - UspapiOption, - TelemetryPartitionStrategy, - RegionsOperator, - IsoCountrySubdivisionCode, IsoCountryCode, - BrowserTimeZone, + IsoCountrySubdivisionCode, + RegionsOperator, SignedIabAgreementOption, + TelemetryPartitionStrategy, + UnknownRequestPolicy, + UspapiOption, } from '@transcend-io/privacy-types'; +import { GraphQLClient } from 'graphql-request'; import { - InitialViewState, - BrowserLanguage, - OnConsentExpiry, -} from '@transcend-io/airgap.js-types'; -import { - FETCH_CONSENT_MANAGER_ID, - FETCH_CONSENT_MANAGER, - EXPERIENCES, CONSENT_MANAGER_ANALYTICS_DATA, + EXPERIENCES, + FETCH_CONSENT_MANAGER, + FETCH_CONSENT_MANAGER_ID, FETCH_CONSENT_MANAGER_THEME, } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; diff --git a/src/lib/graphql/fetchDataSubjects.ts b/src/lib/graphql/fetchDataSubjects.ts index 17fcfb54..fcfcb0ed 100644 --- a/src/lib/graphql/fetchDataSubjects.ts +++ b/src/lib/graphql/fetchDataSubjects.ts @@ -1,11 +1,11 @@ -import { GraphQLClient } from 'graphql-request'; -import { CREATE_DATA_SUBJECT, DATA_SUBJECTS } from './gqls'; -import { keyBy, flatten, uniq, difference } from 'lodash-es'; import { RequestActionObjectResolver } from '@transcend-io/privacy-types'; +import colors from 'colors'; +import { GraphQLClient } from 'graphql-request'; +import { difference, flatten, keyBy, uniq } from 'lodash-es'; import { TranscendInput } from '../../codecs'; import { logger } from '../../logger'; -import colors from 'colors'; import { mapSeries } from '../bluebird-replace'; +import { CREATE_DATA_SUBJECT, DATA_SUBJECTS } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface DataSubject { @@ -62,7 +62,7 @@ export async function ensureAllDataSubjectsExist( }: TranscendInput, client: GraphQLClient, fetchAll = false, -): Promise<{ [type in string]: DataSubject }> { +): Promise> { // Only need to fetch data subjects if specified in config const expectedDataSubjects = uniq([ ...flatten(dataSilos.map((silo) => silo['data-subjects'] || []) || []), @@ -122,13 +122,13 @@ export async function ensureAllDataSubjectsExist( */ export function convertToDataSubjectBlockList( dataSubjectTypes: string[], - allDataSubjects: { [type in string]: DataSubject }, + allDataSubjects: Record, ): string[] { - dataSubjectTypes.forEach((type) => { + for (const type of dataSubjectTypes) { if (!allDataSubjects[type]) { throw new Error(`Expected to find data subject definition: ${type}`); } - }); + } return Object.values(allDataSubjects) .filter((silo) => !dataSubjectTypes.includes(silo.type)) @@ -144,13 +144,13 @@ export function convertToDataSubjectBlockList( */ export function convertToDataSubjectAllowlist( dataSubjectTypes: string[], - allDataSubjects: { [type in string]: DataSubject }, + allDataSubjects: Record, ): string[] { - dataSubjectTypes.forEach((type) => { + for (const type of dataSubjectTypes) { if (!allDataSubjects[type]) { throw new Error(`Expected to find data subject definition: ${type}`); } - }); + } return Object.values(allDataSubjects) .filter((silo) => !dataSubjectTypes.includes(silo.type)) diff --git a/src/lib/graphql/fetchIdentifiers.ts b/src/lib/graphql/fetchIdentifiers.ts index 8a778fc6..9ff7b3ef 100644 --- a/src/lib/graphql/fetchIdentifiers.ts +++ b/src/lib/graphql/fetchIdentifiers.ts @@ -1,11 +1,11 @@ -import { GraphQLClient } from 'graphql-request'; import { IdentifierType, RequestAction } from '@transcend-io/privacy-types'; -import { CREATE_IDENTIFIER, IDENTIFIERS, NEW_IDENTIFIER_TYPES } from './gqls'; -import { keyBy, uniq, flatten, difference } from 'lodash-es'; +import colors from 'colors'; +import { GraphQLClient } from 'graphql-request'; +import { difference, flatten, keyBy, uniq } from 'lodash-es'; import { TranscendInput } from '../../codecs'; import { logger } from '../../logger'; -import colors from 'colors'; import { mapSeries } from '../bluebird-replace'; +import { CREATE_IDENTIFIER, IDENTIFIERS, NEW_IDENTIFIER_TYPES } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface Identifier { @@ -98,7 +98,7 @@ export async function fetchIdentifiersAndCreateMissing( }: TranscendInput, client: GraphQLClient, skipPublish = false, -): Promise<{ [k in string]: Identifier }> { +): Promise> { // Grab all existing identifiers const allIdentifiers = await fetchAllIdentifiers(client); @@ -135,7 +135,9 @@ export async function fetchIdentifiersAndCreateMissing( name: string; }[]; }>(client, NEW_IDENTIFIER_TYPES); - const nativeTypesRemaining = newIdentifierTypes.map(({ name }) => name); + const nativeTypesRemaining = new Set( + newIdentifierTypes.map(({ name }) => name), + ); await mapSeries(missingIdentifiers, async (identifier) => { logger.info(colors.magenta(`Creating identifier ${identifier}...`)); const { createIdentifier } = await makeGraphQLRequest<{ @@ -147,9 +149,7 @@ export async function fetchIdentifiersAndCreateMissing( }>(client, CREATE_IDENTIFIER, { input: { name: identifier, - type: nativeTypesRemaining.includes(identifier!) - ? identifier - : 'custom', + type: nativeTypesRemaining.has(identifier!) ? identifier : 'custom', skipPublish, }, }); diff --git a/src/lib/graphql/fetchLargeLanguageModels.ts b/src/lib/graphql/fetchLargeLanguageModels.ts index 98beb69e..4b097340 100644 --- a/src/lib/graphql/fetchLargeLanguageModels.ts +++ b/src/lib/graphql/fetchLargeLanguageModels.ts @@ -1,5 +1,5 @@ -import { GraphQLClient } from 'graphql-request'; import { LargeLanguageModelClient } from '@transcend-io/privacy-types'; +import { GraphQLClient } from 'graphql-request'; import { LARGE_LANGUAGE_MODELS } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; diff --git a/src/lib/graphql/fetchPrompts.ts b/src/lib/graphql/fetchPrompts.ts index b673ea84..fbe02686 100644 --- a/src/lib/graphql/fetchPrompts.ts +++ b/src/lib/graphql/fetchPrompts.ts @@ -1,10 +1,10 @@ -import { GraphQLClient } from 'graphql-request'; -import { PROMPTS, PROMPTS_WITH_VARIABLES } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; import { - PromptStatus, PromptResponseFormat, + PromptStatus, } from '@transcend-io/privacy-types'; +import { GraphQLClient } from 'graphql-request'; +import { PROMPTS, PROMPTS_WITH_VARIABLES } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface Prompt { /** ID of prompt */ @@ -81,7 +81,7 @@ export async function fetchAllPrompts( /** * The basic metadata needed to use a prompt at runtime */ -export type TranscendPromptTemplated = { +export interface TranscendPromptTemplated { /** ID of prompt */ id: string; /** Title of prompt */ @@ -98,12 +98,12 @@ export type TranscendPromptTemplated = { maxTokensToSample?: number; /** Response format */ responseFormat?: PromptResponseFormat; -}; +} /** * The basic metadata needed to use a prompt partial at runtime */ -export type TranscendPromptPartialTemplated = { +export interface TranscendPromptPartialTemplated { /** ID of prompt */ id: string; /** Title of prompt */ @@ -112,32 +112,32 @@ export type TranscendPromptPartialTemplated = { slug: string; /** Content of prompt */ content: string; -}; +} /** * Calculated variables */ -export type PromptCalculatedVariable = { +export interface PromptCalculatedVariable { /** JSON stringified data to template */ data: string | null; /** Name of variable */ name: string; -}; +} /** * Runtime variables */ -export type PromptRuntimeVariable = { +export interface PromptRuntimeVariable { /** Type of variable */ type: string; /** Name of variable */ name: string; -}; +} /** * Metadata useful for filling variables within a prompt */ -export type TranscendPromptsAndVariables = { +export interface TranscendPromptsAndVariables { /** Prompts ready to be templated */ prompts: TranscendPromptTemplated[]; /** Prompt partials */ @@ -146,7 +146,7 @@ export type TranscendPromptsAndVariables = { calculatedVariables: PromptCalculatedVariable[]; /** Runtime variables to be templated */ runtimeVariables: PromptRuntimeVariable[]; -}; +} /** * Fetch prompts with templated variables diff --git a/src/lib/graphql/fetchRequestDataSilo.ts b/src/lib/graphql/fetchRequestDataSilo.ts index 670d5423..5e01d303 100644 --- a/src/lib/graphql/fetchRequestDataSilo.ts +++ b/src/lib/graphql/fetchRequestDataSilo.ts @@ -1,13 +1,13 @@ -import { GraphQLClient } from 'graphql-request'; -import colors from 'colors'; -import cliProgress from 'cli-progress'; -import { REQUEST_DATA_SILOS } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; import { RequestDataSiloStatus, RequestStatus, } from '@transcend-io/privacy-types'; +import cliProgress from 'cli-progress'; +import colors from 'colors'; +import { GraphQLClient } from 'graphql-request'; import { logger } from '../../logger'; +import { REQUEST_DATA_SILOS } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface RequestDataSilo { /** ID of RequestDataSilo */ @@ -47,7 +47,7 @@ export async function fetchRequestDataSilos( }, ): Promise { // create a new progress bar instance and use shades_classic theme - const t0 = new Date().getTime(); + const t0 = Date.now(); const progressBar = new cliProgress.SingleBar( {}, cliProgress.Presets.shades_classic, @@ -92,7 +92,7 @@ export async function fetchRequestDataSilos( } while (shouldContinue); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; // Log completion time diff --git a/src/lib/graphql/formatAttributeValues.ts b/src/lib/graphql/formatAttributeValues.ts index ffc85a13..87af79a8 100644 --- a/src/lib/graphql/formatAttributeValues.ts +++ b/src/lib/graphql/formatAttributeValues.ts @@ -18,17 +18,19 @@ export function formatAttributeValues( ): FormattedAttribute[] { const attributes: FormattedAttribute[] = []; - vals.map((val) => { - let foundKey = attributes.find((att) => att.key === val.attributeKey.name); + vals.map((value) => { + let foundKey = attributes.find( + (att) => att.key === value.attributeKey.name, + ); if (foundKey === undefined) { foundKey = { - key: val.attributeKey.name, - values: [val.name], + key: value.attributeKey.name, + values: [value.name], }; attributes.push(foundKey); } else { - foundKey.values.push(val.name); + foundKey.values.push(value.name); } return attributes; }); diff --git a/src/lib/graphql/gqls/actionItemCollection.ts b/src/lib/graphql/gqls/actionItemCollection.ts index 3fa6a794..581f4c8d 100644 --- a/src/lib/graphql/gqls/actionItemCollection.ts +++ b/src/lib/graphql/gqls/actionItemCollection.ts @@ -1,4 +1,5 @@ import { gql } from 'graphql-request'; + // TODO: https://transcend.height.app/T-27909 - enable optimizations // isExportCsv: true // useMaster: false diff --git a/src/lib/graphql/gqls/consentManager.ts b/src/lib/graphql/gqls/consentManager.ts index de4cca45..72b4428b 100644 --- a/src/lib/graphql/gqls/consentManager.ts +++ b/src/lib/graphql/gqls/consentManager.ts @@ -1,4 +1,3 @@ -/* eslint-disable max-lines */ import { gql } from 'graphql-request'; // TODO: https://transcend.height.app/T-27909 - order by createdAt @@ -409,4 +408,3 @@ export const CREATE_CONSENT_PARTITION = gql` } } `; -/* eslint-enable max-lines */ diff --git a/src/lib/graphql/loginUser.ts b/src/lib/graphql/loginUser.ts index 59851ad8..cb1cb462 100644 --- a/src/lib/graphql/loginUser.ts +++ b/src/lib/graphql/loginUser.ts @@ -1,5 +1,5 @@ import { GraphQLClient } from 'graphql-request'; -import { DETERMINE_LOGIN_METHOD, ASSUME_ROLE, LOGIN } from './gqls'; +import { ASSUME_ROLE, DETERMINE_LOGIN_METHOD, LOGIN } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface OrganizationPreview { @@ -81,7 +81,7 @@ export async function loginUser( // Get login cookie from response const loginCookie = res.headers.get('set-cookie'); - if (!loginCookie || !loginCookie.includes('laravel')) { + if (!loginCookie?.includes('laravel')) { throw new Error('Failed to get login cookie in response'); } diff --git a/src/lib/graphql/makeGraphQLRequest.ts b/src/lib/graphql/makeGraphQLRequest.ts index b29bbe44..ea13b0f8 100644 --- a/src/lib/graphql/makeGraphQLRequest.ts +++ b/src/lib/graphql/makeGraphQLRequest.ts @@ -1,10 +1,10 @@ +import colors from 'colors'; import type { GraphQLClient, RequestDocument, Variables, } from 'graphql-request'; import { logger } from '../../logger'; -import colors from 'colors'; const MAX_RETRIES = 4; @@ -16,7 +16,9 @@ const MAX_RETRIES = 4; */ function sleepPromise(sleepTime: number): Promise { return new Promise((resolve) => { - setTimeout(() => resolve(sleepTime), sleepTime); + setTimeout(() => { + resolve(sleepTime); + }, sleepTime); }); } @@ -46,13 +48,13 @@ export async function makeGraphQLRequest( maxRequests = MAX_RETRIES, ): Promise { let retryCount = 0; - // eslint-disable-next-line no-constant-condition + while (true) { try { const result = await client.request(document, variables, requestHeaders); return result as T; - } catch (err) { - if (err.message.includes('API key is invalid')) { + } catch (error) { + if (error.message.includes('API key is invalid')) { logger.error( colors.red( 'API key is invalid. ' + @@ -63,19 +65,20 @@ export async function makeGraphQLRequest( process.exit(1); } - if (KNOWN_ERRORS.some((msg) => err.message.includes(msg))) { - throw err; + if (KNOWN_ERRORS.some((message) => error.message.includes(message))) { + throw error; } // wait for rate limit to resolve - if (err.message.startsWith('Client error: Too many requests')) { - const rateLimitResetAt = err.response.headers?.get('x-ratelimit-reset'); + if (error.message.startsWith('Client error: Too many requests')) { + const rateLimitResetAt = + error.response.headers?.get('x-ratelimit-reset'); const sleepTime = rateLimitResetAt - ? new Date(rateLimitResetAt).getTime() - new Date().getTime() + 100 + ? new Date(rateLimitResetAt).getTime() - Date.now() + 100 : 1000 * 10; logger.log( colors.yellow( - `DETECTED RATE LIMIT: ${err.message}. Sleeping for ${sleepTime}ms`, + `DETECTED RATE LIMIT: ${error.message}. Sleeping for ${sleepTime}ms`, ), ); @@ -83,12 +86,12 @@ export async function makeGraphQLRequest( } if (retryCount >= maxRequests) { - throw err; + throw error; } retryCount += 1; logger.log( colors.yellow( - `REQUEST FAILED: ${err.message}. Retrying ${retryCount}/${maxRequests}...`, + `REQUEST FAILED: ${error.message}. Retrying ${retryCount}/${maxRequests}...`, ), ); } diff --git a/src/lib/graphql/manageApiKeys.ts b/src/lib/graphql/manageApiKeys.ts index 8a5b7a75..19233b3b 100644 --- a/src/lib/graphql/manageApiKeys.ts +++ b/src/lib/graphql/manageApiKeys.ts @@ -1,7 +1,7 @@ +import { ScopeName } from '@transcend-io/privacy-types'; import { GraphQLClient } from 'graphql-request'; import { CREATE_API_KEY, DELETE_API_KEY } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { ScopeName } from '@transcend-io/privacy-types'; export interface CreatedApiKey { /** ID of API key */ diff --git a/src/lib/graphql/pullTranscendConfiguration.ts b/src/lib/graphql/pullTranscendConfiguration.ts index bf22ebc5..c07bc102 100644 --- a/src/lib/graphql/pullTranscendConfiguration.ts +++ b/src/lib/graphql/pullTranscendConfiguration.ts @@ -1,94 +1,93 @@ -/* eslint-disable max-lines */ +import { LanguageKey } from '@transcend-io/internationalization'; +import { + ActionItemCode, + ConsentTrackerStatus, + RequestAction, +} from '@transcend-io/privacy-types'; +import colors from 'colors'; +import { GraphQLClient } from 'graphql-request'; +import { flatten, keyBy, mapValues } from 'lodash-es'; import { - TranscendInput, - ApiKeyInput, - DataSiloInput, - AttributeInput, ActionInput, - IdentifierInput, - BusinessEntityInput, - EnricherInput, - PromptGroupInput, - DataFlowInput, - PromptPartialInput, - DataSubjectInput, - CookieInput, - PromptInput, - DatapointInput, - FieldInput, - ProcessingPurposeInput, - DataCategoryInput, - VendorInput, + ActionItemCollectionInput, + ActionItemInput, AgentFileInput, AgentFunctionInput, AgentInput, - PolicyInput, - IntlMessageInput, - ActionItemInput, - TeamInput, - ActionItemCollectionInput, + ApiKeyInput, AssessmentInput, - AssessmentTemplateInput, AssessmentSectionInput, AssessmentSectionQuestionInput, - RiskLogicInput, + AssessmentTemplateInput, + AttributeInput, + BusinessEntityInput, ConsentPurpose, + CookieInput, + DataCategoryInput, + DataFlowInput, + DatapointInput, + DataSiloInput, + DataSubjectInput, + EnricherInput, + FieldInput, + IdentifierInput, + IntlMessageInput, + PolicyInput, + ProcessingPurposeInput, + PromptGroupInput, + PromptInput, + PromptPartialInput, + RiskLogicInput, + TeamInput, + TranscendInput, + VendorInput, } from '../../codecs'; -import { - RequestAction, - ConsentTrackerStatus, - ActionItemCode, -} from '@transcend-io/privacy-types'; -import { GraphQLClient } from 'graphql-request'; -import { flatten, keyBy, mapValues } from 'lodash-es'; -import { fetchEnrichedDataSilos } from './syncDataSilos'; -import { - convertToDataSubjectAllowlist, - fetchAllDataSubjects, -} from './fetchDataSubjects'; +import { TranscendPullResource } from '../../enums'; +import { logger } from '../../logger'; +import { fetchAllActionItemCollections } from './fetchAllActionItemCollections'; +import { fetchAllActionItems } from './fetchAllActionItems'; +import { fetchAllActions } from './fetchAllActions'; +import { fetchAllAgentFiles } from './fetchAllAgentFiles'; +import { fetchAllAgentFunctions } from './fetchAllAgentFunctions'; +import { fetchAllAgents } from './fetchAllAgents'; +import { fetchAllAssessments } from './fetchAllAssessments'; +import { fetchAllAssessmentTemplates } from './fetchAllAssessmentTemplates'; +import { fetchAllAttributes } from './fetchAllAttributes'; +import { fetchAllBusinessEntities } from './fetchAllBusinessEntities'; +import { fetchAllCookies } from './fetchAllCookies'; +import { fetchAllDataCategories } from './fetchAllDataCategories'; +import { fetchAllDataFlows } from './fetchAllDataFlows'; +import { fetchAllMessages } from './fetchAllMessages'; +import { fetchAllPolicies } from './fetchAllPolicies'; +import { fetchAllPrivacyCenters } from './fetchAllPrivacyCenters'; +import { fetchAllProcessingPurposes } from './fetchAllProcessingPurposes'; +import { fetchAllPurposesAndPreferences } from './fetchAllPurposesAndPreferences'; +import { fetchAllTeams } from './fetchAllTeams'; +import { fetchAllVendors } from './fetchAllVendors'; import { fetchApiKeys } from './fetchApiKeys'; import { fetchConsentManager, fetchConsentManagerExperiences, fetchConsentManagerTheme, } from './fetchConsentManagerId'; -import { fetchAllEnrichers } from './syncEnrichers'; -import { fetchAllDataFlows } from './fetchAllDataFlows'; -import { fetchAllBusinessEntities } from './fetchAllBusinessEntities'; -import { fetchAllActions } from './fetchAllActions'; -import { fetchAllAgents } from './fetchAllAgents'; -import { fetchAllAgentFunctions } from './fetchAllAgentFunctions'; -import { fetchAllAgentFiles } from './fetchAllAgentFiles'; -import { fetchAllVendors } from './fetchAllVendors'; -import { fetchAllDataCategories } from './fetchAllDataCategories'; -import { fetchAllProcessingPurposes } from './fetchAllProcessingPurposes'; +import { + convertToDataSubjectAllowlist, + fetchAllDataSubjects, +} from './fetchDataSubjects'; import { fetchAllIdentifiers } from './fetchIdentifiers'; -import { fetchAllPrompts } from './fetchPrompts'; -import { fetchAllPromptPartials } from './fetchPromptPartials'; -import { fetchAllPolicies } from './fetchAllPolicies'; -import { fetchAllPrivacyCenters } from './fetchAllPrivacyCenters'; -import { fetchAllMessages } from './fetchAllMessages'; import { fetchAllPromptGroups } from './fetchPromptGroups'; -import { fetchAllCookies } from './fetchAllCookies'; -import { fetchAllTemplates } from './syncTemplates'; -import { fetchAllAttributes } from './fetchAllAttributes'; +import { fetchAllPromptPartials } from './fetchPromptPartials'; +import { fetchAllPrompts } from './fetchPrompts'; import { formatAttributeValues } from './formatAttributeValues'; -import { logger } from '../../logger'; -import colors from 'colors'; -import { TranscendPullResource } from '../../enums'; -import { fetchAllActionItems } from './fetchAllActionItems'; -import { fetchAllTeams } from './fetchAllTeams'; -import { fetchAllActionItemCollections } from './fetchAllActionItemCollections'; -import { LanguageKey } from '@transcend-io/internationalization'; -import { fetchPartitions } from './syncPartitions'; -import { fetchAllAssessments } from './fetchAllAssessments'; -import { fetchAllAssessmentTemplates } from './fetchAllAssessmentTemplates'; import { AssessmentNestedRule, parseAssessmentDisplayLogic, } from './parseAssessmentDisplayLogic'; import { parseAssessmentRiskLogic } from './parseAssessmentRiskLogic'; -import { fetchAllPurposesAndPreferences } from './fetchAllPurposesAndPreferences'; +import { fetchEnrichedDataSilos } from './syncDataSilos'; +import { fetchAllEnrichers } from './syncEnrichers'; +import { fetchPartitions } from './syncPartitions'; +import { fetchAllTemplates } from './syncTemplates'; export const DEFAULT_TRANSCEND_PULL_RESOURCES = [ TranscendPullResource.DataSilos, @@ -399,14 +398,14 @@ export async function pullTranscendConfiguration( uspapi: consentManager.configuration.uspapi || undefined, // TODO: https://transcend.height.app/T-23919 - reconsider simpler yml shape syncGroups: consentManager.configuration.syncGroups || undefined, - theme: !consentManagerTheme - ? undefined - : { + theme: consentManagerTheme + ? { primaryColor: consentManagerTheme.primaryColor || undefined, fontColor: consentManagerTheme.fontColor || undefined, privacyPolicy: consentManagerTheme.privacyPolicy || undefined, prompt: consentManagerTheme.prompt, - }, + } + : undefined, experiences: consentManagerExperiences.map((experience) => ({ name: experience.name, displayName: experience.displayName || undefined, @@ -611,8 +610,8 @@ export async function pullTranscendConfiguration( title: category ? `${category} - ${name}` : purpose - ? `${purpose} - ${name}` - : title || name || type || '', + ? `${purpose} - ${name}` + : title || name || type || '', }), ), rows: syncedRows.map( @@ -621,8 +620,8 @@ export async function pullTranscendConfiguration( title: category ? `${category} - ${name}` : purpose - ? `${purpose} - ${name}` - : title || name || type || '', + ? `${purpose} - ${name}` + : title || name || type || '', }), ), }), @@ -876,7 +875,8 @@ export async function pullTranscendConfiguration( defaultMessage, targetReactIntlId: targetReactIntlId || undefined, translations: translations.reduce( - (acc, { locale, value }) => Object.assign(acc, { [locale]: value }), + (accumulator, { locale, value }) => + Object.assign(accumulator, { [locale]: value }), {} as Record, ), }), @@ -1436,7 +1436,7 @@ export async function pullTranscendConfiguration( : actions, testRegex: testRegex || undefined, lookerQueryTitle: lookerQueryTitle || undefined, - expirationDuration: parseInt(expirationDuration, 10), + expirationDuration: Number.parseInt(expirationDuration, 10), transitionRequestStatus: transitionRequestStatus || undefined, phoneNumbers: phoneNumbers && phoneNumbers.length > 0 ? phoneNumbers : undefined, @@ -1623,4 +1623,3 @@ export async function pullTranscendConfiguration( } return result; } -/* eslint-enable max-lines */ diff --git a/src/lib/graphql/reportPromptRun.ts b/src/lib/graphql/reportPromptRun.ts index 5dead494..e5c89e40 100644 --- a/src/lib/graphql/reportPromptRun.ts +++ b/src/lib/graphql/reportPromptRun.ts @@ -1,12 +1,12 @@ -import { GraphQLClient } from 'graphql-request'; -import { REPORT_PROMPT_RUN } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; import { - QueueStatus, ChatCompletionRole, - PromptRunProductArea, LargeLanguageModelClient, + PromptRunProductArea, + QueueStatus, } from '@transcend-io/privacy-types'; +import { GraphQLClient } from 'graphql-request'; +import { REPORT_PROMPT_RUN } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface ReportPromptRunInput { /** Name of run */ diff --git a/src/lib/graphql/setResourceAttributes.ts b/src/lib/graphql/setResourceAttributes.ts index 3d82bcb2..b2fb1ca4 100644 --- a/src/lib/graphql/setResourceAttributes.ts +++ b/src/lib/graphql/setResourceAttributes.ts @@ -1,7 +1,7 @@ +import { AttributeSupportedResourceType } from '@transcend-io/privacy-types'; import { GraphQLClient } from 'graphql-request'; import { SET_RESOURCE_ATTRIBUTES } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { AttributeSupportedResourceType } from '@transcend-io/privacy-types'; interface SetResourceAttributesInput { /** ID of resource */ diff --git a/src/lib/graphql/syncAction.ts b/src/lib/graphql/syncAction.ts index 294f135a..1788cbec 100644 --- a/src/lib/graphql/syncAction.ts +++ b/src/lib/graphql/syncAction.ts @@ -1,12 +1,12 @@ -import { ActionInput } from '../../codecs'; -import { GraphQLClient } from 'graphql-request'; -import { UPDATE_ACTION } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { difference } from 'lodash-es'; import { IsoCountryCode, IsoCountrySubdivisionCode, } from '@transcend-io/privacy-types'; +import { GraphQLClient } from 'graphql-request'; +import { difference } from 'lodash-es'; +import { ActionInput } from '../../codecs'; +import { UPDATE_ACTION } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; const ALL_COUNTRIES_AND_SUBDIVISIONS = [ ...Object.values(IsoCountryCode), diff --git a/src/lib/graphql/syncActionItemCollections.ts b/src/lib/graphql/syncActionItemCollections.ts index 404f780b..1f4db10d 100644 --- a/src/lib/graphql/syncActionItemCollections.ts +++ b/src/lib/graphql/syncActionItemCollections.ts @@ -1,18 +1,18 @@ -import { ActionItemCollectionInput } from '../../codecs'; +import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; -import { mapSeries } from '../bluebird-replace'; -import { - UPDATE_ACTION_ITEM_COLLECTION, - CREATE_ACTION_ITEM_COLLECTION, -} from './gqls'; -import { logger } from '../../logger'; import { keyBy } from 'lodash-es'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import colors from 'colors'; +import { ActionItemCollectionInput } from '../../codecs'; +import { logger } from '../../logger'; +import { mapSeries } from '../bluebird-replace'; import { ActionItemCollection, fetchAllActionItemCollections, } from './fetchAllActionItemCollections'; +import { + CREATE_ACTION_ITEM_COLLECTION, + UPDATE_ACTION_ITEM_COLLECTION, +} from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; /** * Input to create a new action item collection @@ -85,12 +85,11 @@ export async function syncActionItemCollections( ); // Fetch existing - const existingActionItemCollections = await fetchAllActionItemCollections( - client, - ); + const existingActionItemCollections = + await fetchAllActionItemCollections(client); // Look up by title - const collectionByTitle: { [k in string]: ActionItemCollection } = keyBy( + const collectionByTitle: Record = keyBy( existingActionItemCollections, 'title', ); @@ -109,11 +108,11 @@ export async function syncActionItemCollections( `Successfully created action item collection "${input.title}"!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to create action item collection "${input.title}"! - ${err.message}`, + `Failed to create action item collection "${input.title}"! - ${error.message}`, ), ); } @@ -131,11 +130,11 @@ export async function syncActionItemCollections( `Successfully synced action item collection "${input.title}"!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync action item collection "${input.title}"! - ${err.message}`, + `Failed to sync action item collection "${input.title}"! - ${error.message}`, ), ); } diff --git a/src/lib/graphql/syncActionItems.ts b/src/lib/graphql/syncActionItems.ts index 095f8118..e12d15d9 100644 --- a/src/lib/graphql/syncActionItems.ts +++ b/src/lib/graphql/syncActionItems.ts @@ -1,17 +1,17 @@ -import { ActionItemInput } from '../../codecs'; -import { uniq, keyBy, chunk } from 'lodash-es'; +import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; -import { mapSeries } from '../bluebird-replace'; -import { UPDATE_ACTION_ITEMS, CREATE_ACTION_ITEMS } from './gqls'; +import { chunk, keyBy, uniq } from 'lodash-es'; +import { ActionItemInput } from '../../codecs'; import { logger } from '../../logger'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import colors from 'colors'; -import { fetchAllActionItems, ActionItem } from './fetchAllActionItems'; +import { mapSeries } from '../bluebird-replace'; import { ActionItemCollection, fetchAllActionItemCollections, } from './fetchAllActionItemCollections'; +import { ActionItem, fetchAllActionItems } from './fetchAllActionItems'; import { Attribute, fetchAllAttributes } from './fetchAllAttributes'; +import { CREATE_ACTION_ITEMS, UPDATE_ACTION_ITEMS } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; /** * Input to create a new actionItem @@ -24,10 +24,10 @@ import { Attribute, fetchAllAttributes } from './fetchAllAttributes'; export async function createActionItems( client: GraphQLClient, actionItems: ActionItemInput[], - actionItemCollectionByTitle: { [k in string]: ActionItemCollection }, + actionItemCollectionByTitle: Record, // TODO: https://transcend.height.app/T-38961 - insert attributes // eslint-disable-next-line @typescript-eslint/no-unused-vars - attributeKeysByName: { [k in string]: Attribute } = {}, + attributeKeysByName: Record = {}, ): Promise { // TODO: https://transcend.height.app/T-38961 - insert attributes // const getAttribute = (key: string): string => { @@ -81,9 +81,7 @@ export async function updateActionItem( client: GraphQLClient, input: ActionItemInput, actionItemId: string, - attributeKeysByName: { - [k in string]: Attribute; - } = {}, + attributeKeysByName: Record = {}, ): Promise { const getAttribute = (key: string): string => { const existing = attributeKeysByName[key]; @@ -174,21 +172,21 @@ export async function syncActionItems( ]); // Look up by title - const actionItemCollectionByTitle: { [k in string]: ActionItemCollection } = + const actionItemCollectionByTitle: Record = keyBy(existingActionItemCollections, 'title'); - const actionItemByTitle: { [k in string]: ActionItem } = keyBy( + const actionItemByTitle: Record = keyBy( existingActionItems, actionItemToUniqueCode, ); const attributeKeysByName = keyBy(attributeKeys, 'name'); - const actionItemByCxId: { [k in string]: ActionItem } = keyBy( + const actionItemByCxId: Record = keyBy( existingActionItems.filter((x) => !!x.customerExperienceActionItemIds), ({ customerExperienceActionItemIds }) => customerExperienceActionItemIds[0], ); // Ensure all collections exist const missingCollections = uniq( - inputs.map((input) => input.collections).flat(), + inputs.flatMap((input) => input.collections), ).filter((collectionTitle) => !actionItemCollectionByTitle[collectionTitle]); if (missingCollections.length > 0) { logger.info( @@ -225,10 +223,10 @@ export async function syncActionItems( `Successfully created "${newActionItems.length}" actionItems!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( - colors.red(`Failed to create action items! - ${err.message}`), + colors.red(`Failed to create action items! - ${error.message}`), ); } } @@ -247,11 +245,11 @@ export async function syncActionItems( logger.info( colors.green(`Successfully synced action item "${input.title}"!`), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync action item "${input.title}"! - ${err.message}`, + `Failed to sync action item "${input.title}"! - ${error.message}`, ), ); } diff --git a/src/lib/graphql/syncAgentFiles.ts b/src/lib/graphql/syncAgentFiles.ts index 3207aa8e..c83804d3 100644 --- a/src/lib/graphql/syncAgentFiles.ts +++ b/src/lib/graphql/syncAgentFiles.ts @@ -1,12 +1,12 @@ -import { AgentFileInput } from '../../codecs'; +import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; -import { mapSeries } from '../bluebird-replace'; -import { UPDATE_AGENT_FILES, CREATE_AGENT_FILE } from './gqls'; -import { logger } from '../../logger'; import { keyBy } from 'lodash-es'; +import { AgentFileInput } from '../../codecs'; +import { logger } from '../../logger'; +import { mapSeries } from '../bluebird-replace'; +import { AgentFile, fetchAllAgentFiles } from './fetchAllAgentFiles'; +import { CREATE_AGENT_FILE, UPDATE_AGENT_FILES } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import colors from 'colors'; -import { fetchAllAgentFiles, AgentFile } from './fetchAllAgentFiles'; /** * Input to create a new agent file @@ -86,9 +86,10 @@ export async function syncAgentFiles( const existingAgentFiles = await fetchAllAgentFiles(client); // Look up by name - const agentFileByName: { - [k in string]: Pick; - } = keyBy(existingAgentFiles, 'name'); + const agentFileByName: Record< + string, + Pick + > = keyBy(existingAgentFiles, 'name'); // Create new agent files const newAgentFiles = inputs.filter((input) => !agentFileByName[input.name]); @@ -101,11 +102,11 @@ export async function syncAgentFiles( logger.info( colors.green(`Successfully synced agent file "${agentFile.name}"!`), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync agent file "${agentFile.name}"! - ${err.message}`, + `Failed to sync agent file "${agentFile.name}"! - ${error.message}`, ), ); } @@ -121,11 +122,11 @@ export async function syncAgentFiles( logger.info( colors.green(`Successfully synced "${inputs.length}" agent files!`), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync "${inputs.length}" agent files! - ${err.message}`, + `Failed to sync "${inputs.length}" agent files! - ${error.message}`, ), ); } diff --git a/src/lib/graphql/syncAgentFunctions.ts b/src/lib/graphql/syncAgentFunctions.ts index 2faa7b66..ca4b949e 100644 --- a/src/lib/graphql/syncAgentFunctions.ts +++ b/src/lib/graphql/syncAgentFunctions.ts @@ -1,15 +1,15 @@ -import { AgentFunctionInput } from '../../codecs'; +import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; -import { mapSeries } from '../bluebird-replace'; -import { UPDATE_AGENT_FUNCTIONS, CREATE_AGENT_FUNCTION } from './gqls'; -import { logger } from '../../logger'; import { keyBy } from 'lodash-es'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import colors from 'colors'; +import { AgentFunctionInput } from '../../codecs'; +import { logger } from '../../logger'; +import { mapSeries } from '../bluebird-replace'; import { - fetchAllAgentFunctions, AgentFunction, + fetchAllAgentFunctions, } from './fetchAllAgentFunctions'; +import { CREATE_AGENT_FUNCTION, UPDATE_AGENT_FUNCTIONS } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; /** * Input to create a new agent function @@ -84,9 +84,10 @@ export async function syncAgentFunctions( const existingAgentFunctions = await fetchAllAgentFunctions(client); // Look up by name - const agentFunctionByName: { - [k in string]: Pick; - } = keyBy(existingAgentFunctions, 'name'); + const agentFunctionByName: Record< + string, + Pick + > = keyBy(existingAgentFunctions, 'name'); // Create new agent functions const newAgentFunctions = inputs.filter( @@ -103,11 +104,11 @@ export async function syncAgentFunctions( `Successfully synced agent function "${agentFunction.name}"!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync agent function "${agentFunction.name}"! - ${err.message}`, + `Failed to sync agent function "${agentFunction.name}"! - ${error.message}`, ), ); } @@ -123,11 +124,11 @@ export async function syncAgentFunctions( logger.info( colors.green(`Successfully synced "${inputs.length}" agent functions!`), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync "${inputs.length}" agent functions! - ${err.message}`, + `Failed to sync "${inputs.length}" agent functions! - ${error.message}`, ), ); } diff --git a/src/lib/graphql/syncAgents.ts b/src/lib/graphql/syncAgents.ts index 56037b80..9a1b1659 100644 --- a/src/lib/graphql/syncAgents.ts +++ b/src/lib/graphql/syncAgents.ts @@ -1,12 +1,12 @@ -import { AgentInput } from '../../codecs'; +import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; -import { mapSeries } from '../bluebird-replace'; -import { UPDATE_AGENTS, CREATE_AGENT } from './gqls'; -import { logger } from '../../logger'; import { keyBy } from 'lodash-es'; +import { AgentInput } from '../../codecs'; +import { logger } from '../../logger'; +import { mapSeries } from '../bluebird-replace'; +import { Agent, fetchAllAgents } from './fetchAllAgents'; +import { CREATE_AGENT, UPDATE_AGENTS } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import colors from 'colors'; -import { fetchAllAgents, Agent } from './fetchAllAgents'; /** * Input to create a new agent @@ -87,9 +87,10 @@ export async function syncAgents( const existingAgents = await fetchAllAgents(client); // Look up by name - const agentByName: { - [k in string]: Pick; - } = keyBy(existingAgents, 'name'); + const agentByName: Record< + string, + Pick + > = keyBy(existingAgents, 'name'); // Create new agents const newAgents = inputs.filter((input) => !agentByName[input.name]); @@ -100,10 +101,10 @@ export async function syncAgents( const newAgent = await createAgent(client, agent); agentByName[newAgent.name] = newAgent; logger.info(colors.green(`Successfully synced agent "${agent.name}"!`)); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( - colors.red(`Failed to sync agent "${agent.name}"! - ${err.message}`), + colors.red(`Failed to sync agent "${agent.name}"! - ${error.message}`), ); } }); @@ -116,10 +117,12 @@ export async function syncAgents( inputs.map((input) => [input, agentByName[input.name].id]), ); logger.info(colors.green(`Successfully synced "${inputs.length}" agents!`)); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( - colors.red(`Failed to sync "${inputs.length}" agents ! - ${err.message}`), + colors.red( + `Failed to sync "${inputs.length}" agents ! - ${error.message}`, + ), ); } diff --git a/src/lib/graphql/syncAttribute.ts b/src/lib/graphql/syncAttribute.ts index e0c093f8..f902ef43 100644 --- a/src/lib/graphql/syncAttribute.ts +++ b/src/lib/graphql/syncAttribute.ts @@ -1,7 +1,10 @@ -import { AttributeInput } from '../../codecs'; import colors from 'colors'; -import { keyBy, difference, groupBy } from 'lodash-es'; import { GraphQLClient } from 'graphql-request'; +import { difference, groupBy, keyBy } from 'lodash-es'; +import { AttributeInput } from '../../codecs'; +import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; +import { Attribute } from './fetchAllAttributes'; import { CREATE_ATTRIBUTE, CREATE_ATTRIBUTE_VALUES, @@ -10,9 +13,6 @@ import { UPDATE_ATTRIBUTE_VALUES, } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { Attribute } from './fetchAllAttributes'; -import { map } from '../bluebird-replace'; -import { logger } from '../../logger'; /** * Sync attribute @@ -42,7 +42,16 @@ export async function syncAttribute( // create or update attribute key let attributeKeyId: string; - if (!existingAttribute) { + if (existingAttribute) { + await makeGraphQLRequest(client, UPDATE_ATTRIBUTE, { + attributeKeyId: existingAttribute.id, + description: existingAttribute.isCustom + ? attribute.description + : undefined, + ...input, + }); + attributeKeyId = existingAttribute.id; + } else { const { createAttributeKey: { attributeKey }, } = await makeGraphQLRequest<{ @@ -60,15 +69,6 @@ export async function syncAttribute( ...input, }); attributeKeyId = attributeKey.id; - } else { - await makeGraphQLRequest(client, UPDATE_ATTRIBUTE, { - attributeKeyId: existingAttribute.id, - description: existingAttribute.isCustom - ? attribute.description - : undefined, - ...input, - }); - attributeKeyId = existingAttribute.id; } // upsert attribute values diff --git a/src/lib/graphql/syncBusinessEntities.ts b/src/lib/graphql/syncBusinessEntities.ts index 23e81cfc..3b6ce91b 100644 --- a/src/lib/graphql/syncBusinessEntities.ts +++ b/src/lib/graphql/syncBusinessEntities.ts @@ -1,15 +1,15 @@ -import { BusinessEntityInput } from '../../codecs'; +import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; -import { mapSeries } from '../bluebird-replace'; -import { UPDATE_BUSINESS_ENTITIES, CREATE_BUSINESS_ENTITY } from './gqls'; +import { chunk, keyBy } from 'lodash-es'; +import { BusinessEntityInput } from '../../codecs'; import { logger } from '../../logger'; -import { keyBy, chunk } from 'lodash-es'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; +import { mapSeries } from '../bluebird-replace'; import { - fetchAllBusinessEntities, BusinessEntity, + fetchAllBusinessEntities, } from './fetchAllBusinessEntities'; -import colors from 'colors'; +import { CREATE_BUSINESS_ENTITY, UPDATE_BUSINESS_ENTITIES } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; /** * Input to create a new business entity @@ -119,11 +119,11 @@ export async function syncBusinessEntities( `Successfully synced business entity "${businessEntity.title}"!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync business entity "${businessEntity.title}"! - ${err.message}`, + `Failed to sync business entity "${businessEntity.title}"! - ${error.message}`, ), ); } @@ -141,11 +141,11 @@ export async function syncBusinessEntities( logger.info( colors.green(`Successfully synced "${inputs.length}" business entities!`), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync "${inputs.length}" business entities ! - ${err.message}`, + `Failed to sync "${inputs.length}" business entities ! - ${error.message}`, ), ); } diff --git a/src/lib/graphql/syncCodePackages.ts b/src/lib/graphql/syncCodePackages.ts index 6ef4e8de..8d4ddf84 100644 --- a/src/lib/graphql/syncCodePackages.ts +++ b/src/lib/graphql/syncCodePackages.ts @@ -1,15 +1,15 @@ -import { chunk, uniq, keyBy, uniqBy } from 'lodash-es'; +import { CodePackageType } from '@transcend-io/privacy-types'; import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; -import { CodePackage, fetchAllCodePackages } from './fetchAllCodePackages'; +import { chunk, keyBy, uniq, uniqBy } from 'lodash-es'; +import { CodePackageInput, RepositoryInput } from '../../codecs'; import { logger } from '../../logger'; -import { syncSoftwareDevelopmentKits } from './syncSoftwareDevelopmentKits'; import { map, mapSeries } from '../bluebird-replace'; -import { CodePackageInput, RepositoryInput } from '../../codecs'; -import { CodePackageType } from '@transcend-io/privacy-types'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; +import { CodePackage, fetchAllCodePackages } from './fetchAllCodePackages'; import { CREATE_CODE_PACKAGE, UPDATE_CODE_PACKAGES } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; import { syncRepositories } from './syncRepositories'; +import { syncSoftwareDevelopmentKits } from './syncSoftwareDevelopmentKits'; const CHUNK_SIZE = 100; @@ -145,14 +145,12 @@ export async function syncCodePackages( syncSoftwareDevelopmentKits( client, uniqBy( - codePackages - .map(({ type, softwareDevelopmentKits = [] }) => - softwareDevelopmentKits.map(({ name }) => ({ - name, - codePackageType: type, - })), - ) - .flat(), + codePackages.flatMap(({ type, softwareDevelopmentKits = [] }) => + softwareDevelopmentKits.map(({ name }) => ({ + name, + codePackageType: type, + })), + ), ({ name, codePackageType }) => `${name}${LOOKUP_SPLIT_KEY}${codePackageType}`, ), @@ -166,7 +164,7 @@ export async function syncCodePackages( ({ name: repositoryName, url: `https://github.com/${repositoryName}`, - } as RepositoryInput), + }) as RepositoryInput, ), ), ]); @@ -233,9 +231,11 @@ export async function syncCodePackages( `Successfully synced ${newCodePackages.length} code packages!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; - logger.info(colors.red(`Failed to create code packages! - ${err.message}`)); + logger.info( + colors.red(`Failed to create code packages! - ${error.message}`), + ); } // Update existing codePackages @@ -282,10 +282,10 @@ export async function syncCodePackages( logger.info( colors.green(`Successfully updated "${chunk.length}" code packages!`), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( - colors.red(`Failed to update code packages! - ${err.message}`), + colors.red(`Failed to update code packages! - ${error.message}`), ); } }); diff --git a/src/lib/graphql/syncConfigurationToTranscend.ts b/src/lib/graphql/syncConfigurationToTranscend.ts index f59d9d8f..eaa2b390 100644 --- a/src/lib/graphql/syncConfigurationToTranscend.ts +++ b/src/lib/graphql/syncConfigurationToTranscend.ts @@ -1,47 +1,46 @@ -/* eslint-disable max-lines */ -import { TranscendInput } from '../../codecs'; +import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; +import { TranscendInput } from '../../codecs'; import { logger } from '../../logger'; -import colors from 'colors'; import { map } from '../bluebird-replace'; +import { fetchAllActions } from './fetchAllActions'; +import { fetchAllAttributes } from './fetchAllAttributes'; +import { fetchApiKeys } from './fetchApiKeys'; +import { + ensureAllDataSubjectsExist, + fetchAllDataSubjects, +} from './fetchDataSubjects'; import { fetchIdentifiersAndCreateMissing, Identifier, } from './fetchIdentifiers'; -import { syncIdentifier } from './syncIdentifier'; -import { syncEnricher } from './syncEnrichers'; +import { syncAction } from './syncAction'; +import { syncActionItemCollections } from './syncActionItemCollections'; +import { syncActionItems } from './syncActionItems'; +import { syncAgentFiles } from './syncAgentFiles'; +import { syncAgentFunctions } from './syncAgentFunctions'; +import { syncAgents } from './syncAgents'; import { syncAttribute } from './syncAttribute'; -import { syncDataSiloDependencies, syncDataSilos } from './syncDataSilos'; +import { syncBusinessEntities } from './syncBusinessEntities'; +import { syncConsentManager } from './syncConsentManager'; import { syncCookies } from './syncCookies'; -import { - fetchAllDataSubjects, - ensureAllDataSubjectsExist, -} from './fetchDataSubjects'; -import { syncTeams } from './syncTeams'; +import { syncDataCategories } from './syncDataCategories'; +import { syncDataFlows } from './syncDataFlows'; +import { syncDataSiloDependencies, syncDataSilos } from './syncDataSilos'; import { syncDataSubject } from './syncDataSubject'; -import { fetchApiKeys } from './fetchApiKeys'; -import { syncPrompts } from './syncPrompts'; -import { syncPolicies } from './syncPolicies'; +import { syncEnricher } from './syncEnrichers'; +import { syncIdentifier } from './syncIdentifier'; import { syncIntlMessages } from './syncIntlMessages'; +import { syncPartitions } from './syncPartitions'; +import { syncPolicies } from './syncPolicies'; import { syncPrivacyCenter } from './syncPrivacyCenter'; -import { syncConsentManager } from './syncConsentManager'; -import { fetchAllAttributes } from './fetchAllAttributes'; -import { syncBusinessEntities } from './syncBusinessEntities'; -import { syncDataFlows } from './syncDataFlows'; -import { syncAction } from './syncAction'; -import { syncTemplate } from './syncTemplates'; -import { fetchAllActions } from './fetchAllActions'; -import { syncPromptPartials } from './syncPromptPartials'; +import { syncProcessingPurposes } from './syncProcessingPurposes'; import { syncPromptGroups } from './syncPromptGroups'; -import { syncAgents } from './syncAgents'; -import { syncActionItemCollections } from './syncActionItemCollections'; -import { syncActionItems } from './syncActionItems'; -import { syncAgentFunctions } from './syncAgentFunctions'; -import { syncAgentFiles } from './syncAgentFiles'; +import { syncPromptPartials } from './syncPromptPartials'; +import { syncPrompts } from './syncPrompts'; +import { syncTeams } from './syncTeams'; +import { syncTemplate } from './syncTemplates'; import { syncVendors } from './syncVendors'; -import { syncDataCategories } from './syncDataCategories'; -import { syncProcessingPurposes } from './syncProcessingPurposes'; -import { syncPartitions } from './syncPartitions'; const CONCURRENCY = 10; @@ -116,7 +115,7 @@ export async function syncConfigurationToTranscend( client, !publishToPrivacyCenter, ) - : ({} as { [k in string]: Identifier }), + : ({} as Record), // Grab all data subjects in the organization dataSilos || dataSubjects || enrichers ? ensureAllDataSubjectsExist(input, client) @@ -125,7 +124,7 @@ export async function syncConfigurationToTranscend( dataSilos && dataSilos .map((dataSilo) => dataSilo['api-key-title'] || []) - .reduce((acc, lst) => acc + lst.length, 0) > 0 + .reduce((accumulator, lst) => accumulator + lst.length, 0) > 0 ? fetchApiKeys(input, client) : {}, ]); @@ -136,10 +135,10 @@ export async function syncConfigurationToTranscend( try { await syncConsentManager(client, consentManager); logger.info(colors.green('Successfully synced consent manager!')); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( - colors.red(`Failed to sync consent manager! - ${err.message}`), + colors.red(`Failed to sync consent manager! - ${error.message}`), ); } } @@ -177,11 +176,11 @@ export async function syncConfigurationToTranscend( logger.info( colors.green(`Successfully synced template "${template.title}"!`), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync template "${template.title}"! - ${err.message}`, + `Failed to sync template "${template.title}"! - ${error.message}`, ), ); } @@ -277,7 +276,7 @@ export async function syncConfigurationToTranscend( attributes, async (attribute) => { const existing = existingAttributes.find( - (attr) => attr.name === attribute.name, + (attribute_) => attribute_.name === attribute.name, ); logger.info(colors.magenta(`Syncing attribute "${attribute.name}"...`)); @@ -289,11 +288,11 @@ export async function syncConfigurationToTranscend( logger.info( colors.green(`Successfully synced attribute "${attribute.name}"!`), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync attribute "${attribute.name}"! - ${err.message}`, + `Failed to sync attribute "${attribute.name}"! - ${error.message}`, ), ); } @@ -327,11 +326,11 @@ export async function syncConfigurationToTranscend( logger.info( colors.green(`Successfully synced enricher "${enricher.title}"!`), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync enricher "${enricher.title}"! - ${err.message}`, + `Failed to sync enricher "${enricher.title}"! - ${error.message}`, ), ); } @@ -374,11 +373,11 @@ export async function syncConfigurationToTranscend( `Successfully synced identifier "${identifier.type}"!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync identifier "${identifier.type}"! - ${err.message}`, + `Failed to sync identifier "${identifier.type}"! - ${error.message}`, ), ); } @@ -417,11 +416,11 @@ export async function syncConfigurationToTranscend( logger.info( colors.green(`Successfully synced action "${action.type}"!`), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync action "${action.type}"! - ${err.message}`, + `Failed to sync action "${action.type}"! - ${error.message}`, ), ); } @@ -466,11 +465,11 @@ export async function syncConfigurationToTranscend( `Successfully synced data subject "${dataSubject.type}"!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync data subject "${dataSubject.type}"! - ${err.message}`, + `Failed to sync data subject "${dataSubject.type}"! - ${error.message}`, ), ); } @@ -523,15 +522,16 @@ export async function syncConfigurationToTranscend( pageSize, }, ); - dataSilos?.forEach((dataSilo) => { - // Queue up dependency update - if (dataSilo['deletion-dependencies']) { - dependencyUpdates.push([ - dataSiloTitleToId[dataSilo.title], - dataSilo['deletion-dependencies'], - ]); + if (dataSilos) + for (const dataSilo of dataSilos) { + // Queue up dependency update + if (dataSilo['deletion-dependencies']) { + dependencyUpdates.push([ + dataSiloTitleToId[dataSilo.title], + dataSilo['deletion-dependencies'], + ]); + } } - }); encounteredError = encounteredError || !success; } @@ -546,4 +546,3 @@ export async function syncConfigurationToTranscend( return encounteredError; } -/* eslint-enable max-lines */ diff --git a/src/lib/graphql/syncConsentManager.ts b/src/lib/graphql/syncConsentManager.ts index 7f1802f5..5184f7aa 100644 --- a/src/lib/graphql/syncConsentManager.ts +++ b/src/lib/graphql/syncConsentManager.ts @@ -1,38 +1,38 @@ +import { + InitialViewState, + OnConsentExpiry, +} from '@transcend-io/airgap.js-types'; +import colors from 'colors'; +import { GraphQLClient } from 'graphql-request'; +import { keyBy } from 'lodash-es'; import { ConsentManageExperienceInput, ConsentManagerInput, } from '../../codecs'; -import colors from 'colors'; -import { GraphQLClient } from 'graphql-request'; +import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; +import { fetchAllPurposes } from './fetchAllPurposes'; import { - UPDATE_CONSENT_MANAGER_DOMAINS, + fetchConsentManagerExperiences, + fetchConsentManagerId, +} from './fetchConsentManagerId'; +import { fetchPrivacyCenterId } from './fetchPrivacyCenterId'; +import { + CREATE_CONSENT_EXPERIENCE, CREATE_CONSENT_MANAGER, - UPDATE_TOGGLE_USP_API, - UPDATE_CONSENT_MANAGER_PARTITION, - UPDATE_CONSENT_MANAGER_VERSION, + TOGGLE_CONSENT_PRECEDENCE, TOGGLE_TELEMETRY_PARTITION_STRATEGY, TOGGLE_UNKNOWN_COOKIE_POLICY, - TOGGLE_CONSENT_PRECEDENCE, TOGGLE_UNKNOWN_REQUEST_POLICY, UPDATE_CONSENT_EXPERIENCE, - CREATE_CONSENT_EXPERIENCE, + UPDATE_CONSENT_MANAGER_DOMAINS, + UPDATE_CONSENT_MANAGER_PARTITION, UPDATE_CONSENT_MANAGER_THEME, + UPDATE_CONSENT_MANAGER_VERSION, + UPDATE_TOGGLE_USP_API, } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { - fetchConsentManagerId, - fetchConsentManagerExperiences, -} from './fetchConsentManagerId'; -import { keyBy } from 'lodash-es'; -import { map } from '../bluebird-replace'; -import { - InitialViewState, - OnConsentExpiry, -} from '@transcend-io/airgap.js-types'; -import { logger } from '../../logger'; -import { fetchPrivacyCenterId } from './fetchPrivacyCenterId'; import { fetchPartitions } from './syncPartitions'; -import { fetchAllPurposes } from './fetchAllPurposes'; const PURPOSES_LINK = 'https://app.transcend.io/consent-manager/regional-experiences/purposes'; @@ -93,9 +93,9 @@ export async function syncConsentManagerExperiences( onConsentExpiry: exp.onConsentExpiry, consentExpiry: exp.consentExpiry, displayPriority: - exp.displayPriority !== existingExperience.displayPriority - ? exp.displayPriority - : undefined, + exp.displayPriority === existingExperience.displayPriority + ? undefined + : exp.displayPriority, viewState: exp.viewState, purposes: purposeIds, optedOutPurposes: optedOutPurposeIds, @@ -152,9 +152,9 @@ export async function syncConsentManager( // ensure the consent manager is created and deployed try { airgapBundleId = await fetchConsentManagerId(client, 1); - } catch (err) { + } catch (error) { // TODO: https://transcend.height.app/T-23778 - if (err.message.includes('AirgapBundle not found')) { + if (error.message.includes('AirgapBundle not found')) { const privacyCenterId = await fetchPrivacyCenterId(client); const { createConsentManager } = await makeGraphQLRequest<{ @@ -172,7 +172,7 @@ export async function syncConsentManager( }); airgapBundleId = createConsentManager.consentManager.id; } else { - throw err; + throw error; } } diff --git a/src/lib/graphql/syncCookies.ts b/src/lib/graphql/syncCookies.ts index fa464bfd..7fcdf38b 100644 --- a/src/lib/graphql/syncCookies.ts +++ b/src/lib/graphql/syncCookies.ts @@ -1,11 +1,11 @@ -import { GraphQLClient } from 'graphql-request'; -import { logger } from '../../logger'; -import { CookieInput } from '../../codecs'; import colors from 'colors'; -import { UPDATE_OR_CREATE_COOKIES } from './gqls'; +import { GraphQLClient } from 'graphql-request'; import { chunk } from 'lodash-es'; -import { fetchConsentManagerId } from './fetchConsentManagerId'; +import { CookieInput } from '../../codecs'; +import { logger } from '../../logger'; import { mapSeries } from '../bluebird-replace'; +import { fetchConsentManagerId } from './fetchConsentManagerId'; +import { UPDATE_OR_CREATE_COOKIES } from './gqls'; // import { keyBy } from 'lodash-es'; import { makeGraphQLRequest } from './makeGraphQLRequest'; @@ -88,9 +88,9 @@ export async function syncCookies( logger.info(colors.magenta(`Upserting "${cookies.length}" new cookies...`)); await updateOrCreateCookies(client, cookies); logger.info(colors.green(`Successfully synced ${cookies.length} cookies!`)); - } catch (err) { + } catch (error) { encounteredError = true; - logger.info(colors.red(`Failed to create cookies! - ${err.message}`)); + logger.info(colors.red(`Failed to create cookies! - ${error.message}`)); } return !encounteredError; diff --git a/src/lib/graphql/syncDataCategories.ts b/src/lib/graphql/syncDataCategories.ts index 174dfe14..2821bf2b 100644 --- a/src/lib/graphql/syncDataCategories.ts +++ b/src/lib/graphql/syncDataCategories.ts @@ -1,15 +1,15 @@ -import { DataCategoryInput } from '../../codecs'; +import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; -import { mapSeries } from '../bluebird-replace'; -import { UPDATE_DATA_SUB_CATEGORIES, CREATE_DATA_SUB_CATEGORY } from './gqls'; -import { logger } from '../../logger'; import { keyBy } from 'lodash-es'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import colors from 'colors'; +import { DataCategoryInput } from '../../codecs'; +import { logger } from '../../logger'; +import { mapSeries } from '../bluebird-replace'; import { - fetchAllDataCategories, DataSubCategory, + fetchAllDataCategories, } from './fetchAllDataCategories'; +import { CREATE_DATA_SUB_CATEGORY, UPDATE_DATA_SUB_CATEGORIES } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; /** * Input to create a new data category @@ -83,9 +83,10 @@ export async function syncDataCategories( const existingDataCategories = await fetchAllDataCategories(client); // Look up by name - const dataCategoryByName: { - [k in string]: Pick; - } = keyBy( + const dataCategoryByName: Record< + string, + Pick + > = keyBy( existingDataCategories, ({ name, category }) => `${name}:${category}`, ); @@ -107,11 +108,11 @@ export async function syncDataCategories( `Successfully synced data category "${dataCategory.name}"!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync data category "${dataCategory.name}"! - ${err.message}`, + `Failed to sync data category "${dataCategory.name}"! - ${error.message}`, ), ); } @@ -130,11 +131,11 @@ export async function syncDataCategories( logger.info( colors.green(`Successfully synced "${inputs.length}" data categories!`), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync "${inputs.length}" data categories ! - ${err.message}`, + `Failed to sync "${inputs.length}" data categories ! - ${error.message}`, ), ); } diff --git a/src/lib/graphql/syncDataFlows.ts b/src/lib/graphql/syncDataFlows.ts index 075bce47..795fa6de 100644 --- a/src/lib/graphql/syncDataFlows.ts +++ b/src/lib/graphql/syncDataFlows.ts @@ -1,14 +1,14 @@ +import { ConsentTrackerStatus } from '@transcend-io/privacy-types'; +import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; -import { CREATE_DATA_FLOWS, UPDATE_DATA_FLOWS } from './gqls'; import { chunk } from 'lodash-es'; -import { mapSeries } from '../bluebird-replace'; import { DataFlowInput } from '../../codecs'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { fetchConsentManagerId } from './fetchConsentManagerId'; import { logger } from '../../logger'; -import colors from 'colors'; +import { mapSeries } from '../bluebird-replace'; import { fetchAllDataFlows } from './fetchAllDataFlows'; -import { ConsentTrackerStatus } from '@transcend-io/privacy-types'; +import { fetchConsentManagerId } from './fetchConsentManagerId'; +import { CREATE_DATA_FLOWS, UPDATE_DATA_FLOWS } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; const MAX_PAGE_SIZE = 100; @@ -169,9 +169,9 @@ export async function syncDataFlows( logger.info( colors.green(`Successfully synced ${newDataFlows.length} data flows!`), ); - } catch (err) { + } catch (error) { encounteredError = true; - logger.info(colors.red(`Failed to create data flows! - ${err.message}`)); + logger.info(colors.red(`Failed to create data flows! - ${error.message}`)); } // Update existing data flows @@ -188,9 +188,9 @@ export async function syncDataFlows( `Successfully updated "${existingDataFlows.length}" data flows!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; - logger.info(colors.red(`Failed to create data flows! - ${err.message}`)); + logger.info(colors.red(`Failed to create data flows! - ${error.message}`)); } logger.info(colors.green(`Synced "${dataFlows.length}" data flows!`)); diff --git a/src/lib/graphql/syncDataSilos.ts b/src/lib/graphql/syncDataSilos.ts index 2c66f7bb..da3b828b 100644 --- a/src/lib/graphql/syncDataSilos.ts +++ b/src/lib/graphql/syncDataSilos.ts @@ -1,41 +1,40 @@ -/* eslint-disable max-lines */ +import { + ConfidenceLabel, + IsoCountryCode, + IsoCountrySubdivisionCode, + PromptAVendorEmailCompletionLinkType, + PromptAVendorEmailSendType, + RequestActionObjectResolver, + SubDataPointDataSubCategoryGuessStatus, +} from '@transcend-io/privacy-types'; +import { apply } from '@transcend-io/type-utils'; import cliProgress from 'cli-progress'; +import colors from 'colors'; +import { GraphQLClient } from 'graphql-request'; +import { chunk, keyBy, sortBy } from 'lodash-es'; import { DataCategoryInput, DataSiloInput, ProcessingPurposeInput, } from '../../codecs'; -import { GraphQLClient } from 'graphql-request'; import { logger } from '../../logger'; -import colors from 'colors'; -import { mapSeries, map } from '../bluebird-replace'; +import { map, mapSeries } from '../bluebird-replace'; +import { ApiKey } from './fetchApiKeys'; +import { + convertToDataSubjectBlockList, + DataSubject, +} from './fetchDataSubjects'; import { - DATA_SILOS, CREATE_DATA_SILOS, - UPDATE_OR_CREATE_DATA_POINT, DATA_POINTS, - SUB_DATA_POINTS, - UPDATE_DATA_SILOS, + DATA_SILOS, DATA_SILOS_ENRICHED, + SUB_DATA_POINTS, SUB_DATA_POINTS_WITH_GUESSES, + UPDATE_DATA_SILOS, + UPDATE_OR_CREATE_DATA_POINT, } from './gqls'; -import { - convertToDataSubjectBlockList, - DataSubject, -} from './fetchDataSubjects'; -import { ApiKey } from './fetchApiKeys'; -import { - IsoCountryCode, - IsoCountrySubdivisionCode, - PromptAVendorEmailCompletionLinkType, - PromptAVendorEmailSendType, - ConfidenceLabel, - RequestActionObjectResolver, - SubDataPointDataSubCategoryGuessStatus, -} from '@transcend-io/privacy-types'; -import { sortBy, chunk, keyBy } from 'lodash-es'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { apply } from '@transcend-io/type-utils'; export interface DataSiloAttributeValue { /** Key associated to value */ @@ -314,13 +313,13 @@ export async function fetchAllSubDataPoints( ), ); } - } catch (err) { + } catch (error) { logger.error( colors.red( `An error fetching subdatapoints for offset ${offset} for dataPointId=${dataPointId}`, ), ); - throw err; + throw error; } } while (shouldContinue); return sortBy(subDataPoints, 'name'); @@ -392,7 +391,7 @@ export async function fetchAllDataPoints( if (!skipSubDatapoints) { await map( nodes, - /* eslint-disable no-loop-func */ + async (node) => { try { if (debug) { @@ -422,16 +421,16 @@ export async function fetchAllDataPoints( ), ); } - } catch (err) { + } catch (error) { logger.error( colors.red( `An error fetching subdatapoints for ${node.name} datapoint offset ${offset}`, ), ); - throw err; + throw error; } }, - /* eslint-enable no-loop-func */ + { concurrency: 5, }, @@ -659,20 +658,20 @@ export async function syncDataSilos( /** Page size */ pageSize: number; /** The data subjects in the organization */ - dataSubjectsByName: { [type in string]: DataSubject }; + dataSubjectsByName: Record; /** API key title to API key */ - apiKeysByTitle: { [title in string]: ApiKey }; + apiKeysByTitle: Record; }, ): Promise<{ /** Whether successfully updated */ success: boolean; /** A mapping between data silo title to data silo ID */ - dataSiloTitleToId: { [k in string]: string }; + dataSiloTitleToId: Record; }> { let encounteredError = false; // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); logger.info(colors.magenta(`Syncing "${dataSilos.length}" data silos...`)); // Determine the set of data silos that already exist @@ -719,9 +718,9 @@ export async function syncDataSilos( }); // save mapping of title and id - dataSilos.forEach((silo) => { + for (const silo of dataSilos) { existingDataSiloByTitle[silo.title] = silo; - }); + } }); logger.info( @@ -811,7 +810,7 @@ export async function syncDataSilos( ); const totalDataPoints = dataSilos .map(({ datapoints = [] }) => datapoints.length) - .reduce((acc, count) => acc + count, 0); + .reduce((accumulator, count) => accumulator + count, 0); logger.info( colors.magenta( `Syncing "${totalDataPoints}" datapoints from "${dataSilosWithDataPoints.length}" data silos...`, @@ -839,18 +838,18 @@ export async function syncDataSilos( ({ name: key, description, - categories: !categories - ? undefined - : categories.map((category) => ({ + categories: categories + ? categories.map((category) => ({ ...category, name: category.name || 'Other', - })), - purposes: !purposes - ? undefined - : purposes.map((purpose) => ({ + })) + : undefined, + purposes: purposes + ? purposes.map((purpose) => ({ ...purpose, name: purpose.name || 'Other', - })), + })) + : undefined, attributes, accessRequestVisibilityEnabled: rest['access-request-visibility-enabled'], @@ -879,14 +878,14 @@ export async function syncDataSilos( ...(datapoint['data-collection-tag'] ? { dataCollectionTag: datapoint['data-collection-tag'] } : {}), - querySuggestions: !datapoint['privacy-action-queries'] - ? undefined - : Object.entries(datapoint['privacy-action-queries']).map( + querySuggestions: datapoint['privacy-action-queries'] + ? Object.entries(datapoint['privacy-action-queries']).map( ([key, value]) => ({ requestType: key, suggestedQuery: value, }), - ), + ) + : undefined, enabledActions: datapoint['privacy-actions'] || [], // clear out when not specified subDataPoints: fields, }; @@ -916,10 +915,10 @@ export async function syncDataSilos( UPDATE_OR_CREATE_DATA_POINT, payload, ); - } catch (err) { + } catch (error) { logger.info( colors.red( - `\nFailed to update datapoint "${datapoint.key}" for data silo "${title}"! - \n${err.message}`, + `\nFailed to update datapoint "${datapoint.key}" for data silo "${title}"! - \n${error.message}`, ), ); encounteredError = true; @@ -936,7 +935,7 @@ export async function syncDataSilos( ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( @@ -1003,16 +1002,15 @@ export async function syncDataSiloDependencies( `Synced "${dependencyUpdateChunk.length}" data silos!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( `[Batch ${ind + 1}/${dependencyUpdateChunk.length}] ` + - `Failed to update "${dependencyUpdateChunk.length}" silos! - ${err.message}`, + `Failed to update "${dependencyUpdateChunk.length}" silos! - ${error.message}`, ), ); } }); return !encounteredError; } -/* eslint-enable max-lines */ diff --git a/src/lib/graphql/syncDataSubject.ts b/src/lib/graphql/syncDataSubject.ts index dcd8c896..3f55d609 100644 --- a/src/lib/graphql/syncDataSubject.ts +++ b/src/lib/graphql/syncDataSubject.ts @@ -1,6 +1,6 @@ -import { DataSubjectInput } from '../../codecs'; import { GraphQLClient } from 'graphql-request'; -import { UPDATE_DATA_SUBJECT, TOGGLE_DATA_SUBJECT } from './gqls'; +import { DataSubjectInput } from '../../codecs'; +import { TOGGLE_DATA_SUBJECT, UPDATE_DATA_SUBJECT } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; /** @@ -31,7 +31,7 @@ export async function syncDataSubject( adminDashboardDefaultSilentMode: dataSubject.adminDashboardDefaultSilentMode, actions: dataSubject.actions, - skipPublish: skipPublish && typeof dataSubject.active === 'undefined', + skipPublish: skipPublish && dataSubject.active === undefined, }, }); diff --git a/src/lib/graphql/syncEnrichers.ts b/src/lib/graphql/syncEnrichers.ts index 74f3e163..634dff1b 100644 --- a/src/lib/graphql/syncEnrichers.ts +++ b/src/lib/graphql/syncEnrichers.ts @@ -1,6 +1,3 @@ -import { EnricherInput } from '../../codecs'; -import { GraphQLClient } from 'graphql-request'; -import { ENRICHERS, CREATE_ENRICHER, UPDATE_ENRICHER } from './gqls'; import { EnricherType, IsoCountryCode, @@ -8,9 +5,12 @@ import { PreflightRequestStatus, RequestAction, } from '@transcend-io/privacy-types'; +import { GraphQLClient } from 'graphql-request'; +import { EnricherInput } from '../../codecs'; +import { DataSubject } from './fetchDataSubjects'; import { Identifier } from './fetchIdentifiers'; +import { CREATE_ENRICHER, ENRICHERS, UPDATE_ENRICHER } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { DataSubject } from './fetchDataSubjects'; export interface Enricher { /** ID of enricher */ @@ -110,9 +110,9 @@ export async function syncEnricher( /** The enricher input */ enricher: EnricherInput; /** Index of identifiers in the organization */ - identifierByName: { [name in string]: Identifier }; + identifierByName: Record; /** Lookup data subject by name */ - dataSubjectsByName: { [name in string]: DataSubject }; + dataSubjectsByName: Record; }, ): Promise { // Whether to continue looping diff --git a/src/lib/graphql/syncIdentifier.ts b/src/lib/graphql/syncIdentifier.ts index 081b4a3a..dbf53249 100644 --- a/src/lib/graphql/syncIdentifier.ts +++ b/src/lib/graphql/syncIdentifier.ts @@ -1,8 +1,8 @@ -import { IdentifierInput } from '../../codecs'; import { GraphQLClient } from 'graphql-request'; +import { IdentifierInput } from '../../codecs'; +import type { DataSubject } from './fetchDataSubjects'; import { UPDATE_IDENTIFIER } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import type { DataSubject } from './fetchDataSubjects'; /** * Sync the consent manager @@ -21,7 +21,7 @@ export async function syncIdentifier( /** Identifier update input */ identifier: IdentifierInput; /** Data subject lookup by name */ - dataSubjectsByName: { [k in string]: DataSubject }; + dataSubjectsByName: Record; /** Existing identifier Id */ identifierId: string; /** When true, skip publishing to privacy center */ diff --git a/src/lib/graphql/syncIntlMessages.ts b/src/lib/graphql/syncIntlMessages.ts index 0debecf9..4d048f37 100644 --- a/src/lib/graphql/syncIntlMessages.ts +++ b/src/lib/graphql/syncIntlMessages.ts @@ -1,10 +1,10 @@ -import { GraphQLClient } from 'graphql-request'; -import { logger } from '../../logger'; -import { IntlMessageInput } from '../../codecs'; import colors from 'colors'; -import { UPDATE_INTL_MESSAGES } from './gqls'; +import { GraphQLClient } from 'graphql-request'; import { chunk } from 'lodash-es'; +import { IntlMessageInput } from '../../codecs'; +import { logger } from '../../logger'; import { mapSeries } from '../bluebird-replace'; +import { UPDATE_INTL_MESSAGES } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; const MAX_PAGE_SIZE = 100; @@ -26,12 +26,12 @@ export async function updateIntlMessages( ...(message.id.includes('.') ? {} : { id: message.id }), defaultMessage: message.defaultMessage, targetReactIntlId: message.targetReactIntlId, - translations: !message.translations - ? undefined - : Object.entries(message.translations).map(([locale, value]) => ({ + translations: message.translations + ? Object.entries(message.translations).map(([locale, value]) => ({ locale, value, - })), + })) + : undefined, })), }); }); @@ -71,9 +71,9 @@ export async function syncIntlMessages( logger.info( colors.green(`Successfully synced ${messages.length} messages!`), ); - } catch (err) { + } catch (error) { encounteredError = true; - logger.info(colors.red(`Failed to create messages! - ${err.message}`)); + logger.info(colors.red(`Failed to create messages! - ${error.message}`)); } return !encounteredError; diff --git a/src/lib/graphql/syncPartitions.ts b/src/lib/graphql/syncPartitions.ts index 4bebdf4d..88c34c44 100644 --- a/src/lib/graphql/syncPartitions.ts +++ b/src/lib/graphql/syncPartitions.ts @@ -1,12 +1,12 @@ import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; -import { CREATE_CONSENT_PARTITION, CONSENT_PARTITIONS } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { mapSeries } from '../bluebird-replace'; import { difference } from 'lodash-es'; -import { logger } from '../../logger'; import { PartitionInput } from '../../codecs'; +import { logger } from '../../logger'; +import { mapSeries } from '../bluebird-replace'; import { fetchConsentManagerId } from './fetchConsentManagerId'; +import { CONSENT_PARTITIONS, CREATE_CONSENT_PARTITION } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; const PAGE_SIZE = 50; @@ -84,10 +84,10 @@ export async function syncPartitions( logger.info( colors.green(`Successfully created consent partition: ${name}!`), ); - } catch (err) { + } catch (error) { logger.error( colors.red( - `Failed to create consent partition: ${name}! - ${err.message}`, + `Failed to create consent partition: ${name}! - ${error.message}`, ), ); encounteredError = true; diff --git a/src/lib/graphql/syncPolicies.ts b/src/lib/graphql/syncPolicies.ts index 79b8dcb9..4ebb1846 100644 --- a/src/lib/graphql/syncPolicies.ts +++ b/src/lib/graphql/syncPolicies.ts @@ -1,13 +1,13 @@ -import { GraphQLClient } from 'graphql-request'; -import { logger } from '../../logger'; -import { PolicyInput } from '../../codecs'; import colors from 'colors'; -import { UPDATE_POLICIES } from './gqls'; +import { GraphQLClient } from 'graphql-request'; import { chunk, keyBy } from 'lodash-es'; +import { PolicyInput } from '../../codecs'; +import { logger } from '../../logger'; import { mapSeries } from '../bluebird-replace'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { fetchPrivacyCenterId } from './fetchPrivacyCenterId'; import { fetchAllPolicies } from './fetchAllPolicies'; +import { fetchPrivacyCenterId } from './fetchPrivacyCenterId'; +import { UPDATE_POLICIES } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; const MAX_PAGE_SIZE = 100; @@ -97,9 +97,9 @@ export async function syncPolicies( logger.info( colors.green(`Successfully synced ${policies.length} policies!`), ); - } catch (err) { + } catch (error) { encounteredError = true; - logger.info(colors.red(`Failed to create policies! - ${err.message}`)); + logger.info(colors.red(`Failed to create policies! - ${error.message}`)); } return !encounteredError; diff --git a/src/lib/graphql/syncPrivacyCenter.ts b/src/lib/graphql/syncPrivacyCenter.ts index 140fd9df..4c6ea353 100644 --- a/src/lib/graphql/syncPrivacyCenter.ts +++ b/src/lib/graphql/syncPrivacyCenter.ts @@ -1,10 +1,10 @@ -import { PrivacyCenterInput } from '../../codecs'; -import { logger } from '../../logger'; import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; +import { PrivacyCenterInput } from '../../codecs'; +import { logger } from '../../logger'; +import { fetchPrivacyCenterId } from './fetchPrivacyCenterId'; import { UPDATE_PRIVACY_CENTER } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { fetchPrivacyCenterId } from './fetchPrivacyCenterId'; /** * Sync the privacy center @@ -55,10 +55,10 @@ export async function syncPrivacyCenter( }, }); logger.info(colors.green('Successfully synced privacy center!')); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( - colors.red(`Failed to create privacy center! - ${err.message}`), + colors.red(`Failed to create privacy center! - ${error.message}`), ); } diff --git a/src/lib/graphql/syncProcessingPurposes.ts b/src/lib/graphql/syncProcessingPurposes.ts index b5c0ff41..b20526dd 100644 --- a/src/lib/graphql/syncProcessingPurposes.ts +++ b/src/lib/graphql/syncProcessingPurposes.ts @@ -1,18 +1,18 @@ -import { ProcessingPurposeInput } from '../../codecs'; +import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; -import { mapSeries } from '../bluebird-replace'; -import { - UPDATE_PROCESSING_PURPOSE_SUB_CATEGORIES, - CREATE_PROCESSING_PURPOSE_SUB_CATEGORY, -} from './gqls'; -import { logger } from '../../logger'; import { keyBy } from 'lodash-es'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import colors from 'colors'; +import { ProcessingPurposeInput } from '../../codecs'; +import { logger } from '../../logger'; +import { mapSeries } from '../bluebird-replace'; import { fetchAllProcessingPurposes, ProcessingPurposeSubCategory, } from './fetchAllProcessingPurposes'; +import { + CREATE_PROCESSING_PURPOSE_SUB_CATEGORY, + UPDATE_PROCESSING_PURPOSE_SUB_CATEGORIES, +} from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; /** * Input to create a new processing purpose @@ -90,9 +90,10 @@ export async function syncProcessingPurposes( const existingProcessingPurposes = await fetchAllProcessingPurposes(client); // Look up by name - const processingPurposeByName: { - [k in string]: Pick; - } = keyBy( + const processingPurposeByName: Record< + string, + Pick + > = keyBy( existingProcessingPurposes, ({ name, purpose }) => `${name}:${purpose}`, ); @@ -117,11 +118,11 @@ export async function syncProcessingPurposes( `Successfully synced processing purpose "${processingPurpose.name}"!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync processing purpose "${processingPurpose.name}"! - ${err.message}`, + `Failed to sync processing purpose "${processingPurpose.name}"! - ${error.message}`, ), ); } @@ -144,11 +145,11 @@ export async function syncProcessingPurposes( `Successfully synced "${inputs.length}" processing purposes!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync "${inputs.length}" processing purposes ! - ${err.message}`, + `Failed to sync "${inputs.length}" processing purposes ! - ${error.message}`, ), ); } diff --git a/src/lib/graphql/syncPromptGroups.ts b/src/lib/graphql/syncPromptGroups.ts index 1fe6e2f9..178ba8d1 100644 --- a/src/lib/graphql/syncPromptGroups.ts +++ b/src/lib/graphql/syncPromptGroups.ts @@ -1,13 +1,13 @@ -import { PromptGroupInput } from '../../codecs'; import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; -import { UPDATE_PROMPT_GROUPS, CREATE_PROMPT_GROUP } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { map } from '../bluebird-replace'; -import { fetchAllPromptGroups } from './fetchPromptGroups'; import { keyBy } from 'lodash-es'; +import { PromptGroupInput } from '../../codecs'; import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; +import { fetchAllPromptGroups } from './fetchPromptGroups'; import { fetchAllPrompts } from './fetchPrompts'; +import { CREATE_PROMPT_GROUP, UPDATE_PROMPT_GROUPS } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface EditPromptGroupInput { /** Title of prompt group */ @@ -135,9 +135,11 @@ export async function syncPromptGroups( `Successfully synced ${newPromptGroups.length} prompt groups!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; - logger.info(colors.red(`Failed to create prompt groups! - ${err.message}`)); + logger.info( + colors.red(`Failed to create prompt groups! - ${error.message}`), + ); } // Update existing promptGroups @@ -171,9 +173,11 @@ export async function syncPromptGroups( `Successfully updated "${existingPromptGroups.length}" prompt groups!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; - logger.info(colors.red(`Failed to create prompt groups! - ${err.message}`)); + logger.info( + colors.red(`Failed to create prompt groups! - ${error.message}`), + ); } logger.info(colors.green(`Synced "${promptGroups.length}" prompt groups!`)); diff --git a/src/lib/graphql/syncPromptPartials.ts b/src/lib/graphql/syncPromptPartials.ts index c6e6c44e..dcdbe2af 100644 --- a/src/lib/graphql/syncPromptPartials.ts +++ b/src/lib/graphql/syncPromptPartials.ts @@ -1,12 +1,12 @@ -import { PromptPartialInput } from '../../codecs'; import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; -import { UPDATE_PROMPT_PARTIALS, CREATE_PROMPT_PARTIAL } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { map } from '../bluebird-replace'; -import { fetchAllPromptPartials } from './fetchPromptPartials'; import { keyBy } from 'lodash-es'; +import { PromptPartialInput } from '../../codecs'; import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; +import { fetchAllPromptPartials } from './fetchPromptPartials'; +import { CREATE_PROMPT_PARTIAL, UPDATE_PROMPT_PARTIALS } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; /** * Create a new prompt partial @@ -119,10 +119,10 @@ export async function syncPromptPartials( `Successfully synced ${newPromptPartials.length} prompt partials!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( - colors.red(`Failed to create prompt partials! - ${err.message}`), + colors.red(`Failed to create prompt partials! - ${error.message}`), ); } @@ -142,10 +142,10 @@ export async function syncPromptPartials( `Successfully updated "${existingPromptPartials.length}" prompt partials!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( - colors.red(`Failed to create prompt partials! - ${err.message}`), + colors.red(`Failed to create prompt partials! - ${error.message}`), ); } diff --git a/src/lib/graphql/syncPrompts.ts b/src/lib/graphql/syncPrompts.ts index 06d1bea1..ba666e5f 100644 --- a/src/lib/graphql/syncPrompts.ts +++ b/src/lib/graphql/syncPrompts.ts @@ -1,12 +1,12 @@ -import { PromptInput } from '../../codecs'; import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; -import { UPDATE_PROMPTS, CREATE_PROMPT } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { map } from '../bluebird-replace'; -import { fetchAllPrompts } from './fetchPrompts'; import { keyBy } from 'lodash-es'; +import { PromptInput } from '../../codecs'; import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; +import { fetchAllPrompts } from './fetchPrompts'; +import { CREATE_PROMPT, UPDATE_PROMPTS } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; /** * Create a new prompt @@ -110,9 +110,9 @@ export async function syncPrompts( logger.info( colors.green(`Successfully synced ${newPrompts.length} prompts!`), ); - } catch (err) { + } catch (error) { encounteredError = true; - logger.info(colors.red(`Failed to create prompts! - ${err.message}`)); + logger.info(colors.red(`Failed to create prompts! - ${error.message}`)); } // Update existing prompts @@ -127,9 +127,9 @@ export async function syncPrompts( logger.info( colors.green(`Successfully updated "${existingPrompts.length}" prompts!`), ); - } catch (err) { + } catch (error) { encounteredError = true; - logger.info(colors.red(`Failed to create prompts! - ${err.message}`)); + logger.info(colors.red(`Failed to create prompts! - ${error.message}`)); } logger.info(colors.green(`Synced "${prompts.length}" prompts!`)); diff --git a/src/lib/graphql/syncRepositories.ts b/src/lib/graphql/syncRepositories.ts index 78c035af..b0d08aed 100644 --- a/src/lib/graphql/syncRepositories.ts +++ b/src/lib/graphql/syncRepositories.ts @@ -1,12 +1,12 @@ import colors from 'colors'; +import { GraphQLClient } from 'graphql-request'; import { chunk, keyBy } from 'lodash-es'; import { RepositoryInput } from '../../codecs'; -import { GraphQLClient } from 'graphql-request'; -import { UPDATE_REPOSITORIES, CREATE_REPOSITORY } from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { mapSeries, map } from '../bluebird-replace'; -import { fetchAllRepositories, Repository } from './fetchAllRepositories'; import { logger } from '../../logger'; +import { map, mapSeries } from '../bluebird-replace'; +import { fetchAllRepositories, Repository } from './fetchAllRepositories'; +import { CREATE_REPOSITORY, UPDATE_REPOSITORIES } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; const CHUNK_SIZE = 100; @@ -154,9 +154,11 @@ export async function syncRepositories( `Successfully synced ${newRepositories.length} repositories!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; - logger.info(colors.red(`Failed to create repositories! - ${err.message}`)); + logger.info( + colors.red(`Failed to create repositories! - ${error.message}`), + ); } // Update existing repositories @@ -183,10 +185,10 @@ export async function syncRepositories( `Successfully updated "${existingRepositories.length}" repositories!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( - colors.red(`Failed to update repositories! - ${err.message}`), + colors.red(`Failed to update repositories! - ${error.message}`), ); } diff --git a/src/lib/graphql/syncSoftwareDevelopmentKits.ts b/src/lib/graphql/syncSoftwareDevelopmentKits.ts index 5a9ed6fe..62059d8c 100644 --- a/src/lib/graphql/syncSoftwareDevelopmentKits.ts +++ b/src/lib/graphql/syncSoftwareDevelopmentKits.ts @@ -1,19 +1,19 @@ +import { CodePackageType } from '@transcend-io/privacy-types'; import colors from 'colors'; +import { GraphQLClient } from 'graphql-request'; import { chunk, keyBy } from 'lodash-es'; import { SoftwareDevelopmentKitInput } from '../../codecs'; -import { GraphQLClient } from 'graphql-request'; -import { - UPDATE_SOFTWARE_DEVELOPMENT_KITS, - CREATE_SOFTWARE_DEVELOPMENT_KIT, -} from './gqls'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { mapSeries, map } from '../bluebird-replace'; +import { logger } from '../../logger'; +import { map, mapSeries } from '../bluebird-replace'; import { fetchAllSoftwareDevelopmentKits, SoftwareDevelopmentKit, } from './fetchAllSoftwareDevelopmentKits'; -import { logger } from '../../logger'; -import { CodePackageType } from '@transcend-io/privacy-types'; +import { + CREATE_SOFTWARE_DEVELOPMENT_KIT, + UPDATE_SOFTWARE_DEVELOPMENT_KITS, +} from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; const CHUNK_SIZE = 100; @@ -196,11 +196,11 @@ export async function syncSoftwareDevelopmentKits( `Successfully synced ${newSoftwareDevelopmentKits.length} software development kits!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to create software development kits! - ${err.message}`, + `Failed to create software development kits! - ${error.message}`, ), ); } @@ -233,11 +233,11 @@ export async function syncSoftwareDevelopmentKits( `Successfully updated "${existingSoftwareDevelopmentKits.length}" software development kits!`, ), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to update software development kits! - ${err.message}`, + `Failed to update software development kits! - ${error.message}`, ), ); } diff --git a/src/lib/graphql/syncTeams.ts b/src/lib/graphql/syncTeams.ts index 48fcd5bd..7681bee0 100644 --- a/src/lib/graphql/syncTeams.ts +++ b/src/lib/graphql/syncTeams.ts @@ -1,12 +1,12 @@ -import { TeamInput } from '../../codecs'; +import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; -import { mapSeries } from '../bluebird-replace'; -import { UPDATE_TEAM, CREATE_TEAM } from './gqls'; -import { logger } from '../../logger'; import { keyBy } from 'lodash-es'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import colors from 'colors'; +import { TeamInput } from '../../codecs'; +import { logger } from '../../logger'; +import { mapSeries } from '../bluebird-replace'; import { fetchAllTeams, Team } from './fetchAllTeams'; +import { CREATE_TEAM, UPDATE_TEAM } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; /** * Input to create a new team @@ -95,7 +95,7 @@ export async function syncTeams( const existingTeams = await fetchAllTeams(client); // Look up by name - const teamsByName: { [k in string]: Pick } = keyBy( + const teamsByName: Record> = keyBy( existingTeams, 'name', ); @@ -110,10 +110,10 @@ export async function syncTeams( const newTeam = await createTeam(client, team); teamsByName[newTeam.name] = newTeam; logger.info(colors.green(`Successfully created team "${team.name}"!`)); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( - colors.red(`Failed to sync team "${team.name}"! - ${err.message}`), + colors.red(`Failed to sync team "${team.name}"! - ${error.message}`), ); } }); @@ -128,10 +128,10 @@ export async function syncTeams( ); teamsByName[newTeam.name] = newTeam; logger.info(colors.green(`Successfully updated team "${input.name}"!`)); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( - colors.red(`Failed to sync team "${input.name}"! - ${err.message}`), + colors.red(`Failed to sync team "${input.name}"! - ${error.message}`), ); } }); diff --git a/src/lib/graphql/syncTemplates.ts b/src/lib/graphql/syncTemplates.ts index 1445af50..ac8c7dbc 100644 --- a/src/lib/graphql/syncTemplates.ts +++ b/src/lib/graphql/syncTemplates.ts @@ -1,6 +1,6 @@ -import { TemplateInput } from '../../codecs'; import { GraphQLClient } from 'graphql-request'; -import { TEMPLATES, CREATE_TEMPLATE } from './gqls'; +import { TemplateInput } from '../../codecs'; +import { CREATE_TEMPLATE, TEMPLATES } from './gqls'; import { makeGraphQLRequest } from './makeGraphQLRequest'; export interface Template { diff --git a/src/lib/graphql/syncVendors.ts b/src/lib/graphql/syncVendors.ts index 0dfc4bb3..9b25814e 100644 --- a/src/lib/graphql/syncVendors.ts +++ b/src/lib/graphql/syncVendors.ts @@ -1,12 +1,12 @@ -import { VendorInput } from '../../codecs'; +import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; -import { mapSeries } from '../bluebird-replace'; -import { UPDATE_VENDORS, CREATE_VENDOR } from './gqls'; -import { logger } from '../../logger'; import { keyBy } from 'lodash-es'; -import { makeGraphQLRequest } from './makeGraphQLRequest'; -import colors from 'colors'; +import { VendorInput } from '../../codecs'; +import { logger } from '../../logger'; +import { mapSeries } from '../bluebird-replace'; import { fetchAllVendors, Vendor } from './fetchAllVendors'; +import { CREATE_VENDOR, UPDATE_VENDORS } from './gqls'; +import { makeGraphQLRequest } from './makeGraphQLRequest'; /** * Input to create a new vendor @@ -94,7 +94,7 @@ export async function syncVendors( const existingVendors = await fetchAllVendors(client); // Look up by title - const vendorByTitle: { [k in string]: Pick } = keyBy( + const vendorByTitle: Record> = keyBy( existingVendors, 'title', ); @@ -110,10 +110,12 @@ export async function syncVendors( logger.info( colors.green(`Successfully synced vendor "${vendor.title}"!`), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( - colors.red(`Failed to sync vendor "${vendor.title}"! - ${err.message}`), + colors.red( + `Failed to sync vendor "${vendor.title}"! - ${error.message}`, + ), ); } }); @@ -128,11 +130,11 @@ export async function syncVendors( logger.info( colors.green(`Successfully synced "${inputs.length}" vendors!`), ); - } catch (err) { + } catch (error) { encounteredError = true; logger.info( colors.red( - `Failed to sync "${inputs.length}" vendors ! - ${err.message}`, + `Failed to sync "${inputs.length}" vendors ! - ${error.message}`, ), ); } diff --git a/src/lib/graphql/uploadSiloDiscoveryResults.ts b/src/lib/graphql/uploadSiloDiscoveryResults.ts index b99cfc07..5ecc80d5 100644 --- a/src/lib/graphql/uploadSiloDiscoveryResults.ts +++ b/src/lib/graphql/uploadSiloDiscoveryResults.ts @@ -1,9 +1,9 @@ +import { GraphQLClient } from 'graphql-request'; import { chunk } from 'lodash-es'; import { mapSeries } from '../bluebird-replace'; +import { SiloDiscoveryRawResults } from '../code-scanning/findFilesToScan'; import { ADD_SILO_DISCOVERY_RESULTS } from './gqls'; -import { GraphQLClient } from 'graphql-request'; import { makeGraphQLRequest } from './makeGraphQLRequest'; -import { SiloDiscoveryRawResults } from '../code-scanning/findFilesToScan'; const CHUNK_SIZE = 1000; diff --git a/src/lib/helpers/buildEnabledRouteType.ts b/src/lib/helpers/buildEnabledRouteType.ts index adb43b26..77b488fc 100644 --- a/src/lib/helpers/buildEnabledRouteType.ts +++ b/src/lib/helpers/buildEnabledRouteType.ts @@ -1,6 +1,6 @@ +import { valuesOf } from '@transcend-io/type-utils'; import * as t from 'io-ts'; import { EnabledRouteC } from '../../codecs'; -import { valuesOf } from '@transcend-io/type-utils'; import { PathfinderPolicyName } from '../../enums'; /** diff --git a/src/lib/helpers/inquirer.ts b/src/lib/helpers/inquirer.ts index 7c82f96e..151b8c37 100644 --- a/src/lib/helpers/inquirer.ts +++ b/src/lib/helpers/inquirer.ts @@ -1,7 +1,7 @@ +import { ObjByString } from '@transcend-io/type-utils'; import inquirer from 'inquirer'; import autoCompletePrompt from 'inquirer-autocomplete-prompt'; import { fuzzySearch } from '../requests'; -import { ObjByString } from '@transcend-io/type-utils'; /** * Inquirer confirm text @@ -83,11 +83,9 @@ export async function inquirerAutoComplete({ type: 'autocomplete', default: defaultValue, source: (answersSoFar: ObjByString, input: string) => - !input - ? values - : values.filter( - (x) => typeof x === 'string' && fuzzySearch(input, x), - ), + input + ? values.filter((x) => typeof x === 'string' && fuzzySearch(input, x)) + : values, }, ]); return response; diff --git a/src/lib/helpers/parseVariablesFromString.ts b/src/lib/helpers/parseVariablesFromString.ts index 3f909cc6..a187a7f0 100644 --- a/src/lib/helpers/parseVariablesFromString.ts +++ b/src/lib/helpers/parseVariablesFromString.ts @@ -4,20 +4,20 @@ * @param variables - Variables as string * @returns Variables as object */ -export function parseVariablesFromString(variables: string): { - [k in string]: string; -} { +export function parseVariablesFromString( + variables: string, +): Record { // Parse out the variables - const splitVars = variables.split(',').filter((x) => !!x); - const vars: { [k in string]: string } = {}; - splitVars.forEach((variable) => { + const splitVariables = variables.split(',').filter((x) => !!x); + const variables_: Record = {}; + for (const variable of splitVariables) { const [k, v] = variable.split(':'); if (!k || !v) { throw new Error( `Invalid variable: ${variable}. Expected format: key:value`, ); } - vars[k] = v; - }); - return vars; + variables_[k] = v; + } + return variables_; } diff --git a/src/lib/manual-enrichment/enrichPrivacyRequest.ts b/src/lib/manual-enrichment/enrichPrivacyRequest.ts index 44c39864..91b1475a 100644 --- a/src/lib/manual-enrichment/enrichPrivacyRequest.ts +++ b/src/lib/manual-enrichment/enrichPrivacyRequest.ts @@ -1,8 +1,8 @@ +import colors from 'colors'; import type { Got } from 'got'; import * as t from 'io-ts'; -import { logger } from '../../logger'; import { uniq } from 'lodash-es'; -import colors from 'colors'; +import { logger } from '../../logger'; import { splitCsvToList } from '../requests/splitCsvToList'; const ADMIN_URL = @@ -32,29 +32,28 @@ export async function enrichPrivacyRequest( ): Promise { if (!rawId) { // error - const msg = `Request ID must be provided to enricher request.${ + const message = `Request ID must be provided to enricher request.${ index ? ` Found error in row: ${index}` : '' }`; - logger.error(colors.red(msg)); - throw new Error(msg); + logger.error(colors.red(message)); + throw new Error(message); } const id = rawId.toLowerCase(); // Pull out the identifiers - const enrichedIdentifiers = Object.entries(rest).reduce( - (acc, [key, value]) => { - const values = uniq(splitCsvToList(value)); - return values.length === 0 - ? acc - : Object.assign(acc, { - [key]: uniq(splitCsvToList(value)).map((val) => ({ - value: key === 'email' ? val.toLowerCase() : val, - })), - }); - }, - {} as Record, - ); + const enrichedIdentifiers = Object.entries(rest).reduce< + Record + >((accumulator, [key, value]) => { + const values = uniq(splitCsvToList(value)); + return values.length === 0 + ? accumulator + : Object.assign(accumulator, { + [key]: uniq(splitCsvToList(value)).map((value_) => ({ + value: key === 'email' ? value_.toLowerCase() : value_, + })), + }); + }, {}); // Make the GraphQL request try { @@ -74,11 +73,11 @@ export async function enrichPrivacyRequest( colors.green(`Successfully enriched request: ${ADMIN_URL}${id}`), ); return true; - } catch (err) { + } catch (error) { // skip if already enriched if ( - typeof err.response.body === 'string' && - err.response.body.includes('Cannot update a resolved RequestEnricher') + typeof error.response.body === 'string' && + error.response.body.includes('Cannot update a resolved RequestEnricher') ) { logger.warn( colors.magenta( @@ -91,9 +90,9 @@ export async function enrichPrivacyRequest( // error logger.error( colors.red( - `Failed to enricher identifiers for request with id: ${ADMIN_URL}${id} - ${err.message} - ${err.response.body}`, + `Failed to enricher identifiers for request with id: ${ADMIN_URL}${id} - ${error.message} - ${error.response.body}`, ), ); - throw err; + throw error; } } diff --git a/src/lib/manual-enrichment/pullManualEnrichmentIdentifiersToCsv.ts b/src/lib/manual-enrichment/pullManualEnrichmentIdentifiersToCsv.ts index c3650070..cf022bec 100644 --- a/src/lib/manual-enrichment/pullManualEnrichmentIdentifiersToCsv.ts +++ b/src/lib/manual-enrichment/pullManualEnrichmentIdentifiersToCsv.ts @@ -1,20 +1,20 @@ import { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; -import { map } from '../bluebird-replace'; import colors from 'colors'; import { groupBy, uniq } from 'lodash-es'; import { DEFAULT_TRANSCEND_API } from '../../constants'; +import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; import { writeCsv } from '../cron/writeCsv'; import { - PrivacyRequest, - RequestEnricher, - RequestIdentifier, buildTranscendGraphQLClient, createSombraGotInstance, fetchAllRequestEnrichers, fetchAllRequestIdentifiers, fetchAllRequests, + PrivacyRequest, + RequestEnricher, + RequestIdentifier, } from '../graphql'; -import { logger } from '../../logger'; export interface PrivacyRequestWithIdentifiers extends PrivacyRequest { /** Request Enrichers */ @@ -115,26 +115,22 @@ export async function pullManualEnrichmentIdentifiersToCsv({ }) => ({ ...request, // flatten identifiers - ...Object.entries(groupBy(requestIdentifiers, 'name')).reduce( - (acc, [key, values]) => - Object.assign(acc, { - [key]: values.map(({ value }) => value).join(','), - }), - {}, + ...Object.fromEntries( + Object.entries(groupBy(requestIdentifiers, 'name')).map( + ([key, values]) => [key, values.map(({ value }) => value).join(',')], + ), ), // flatten attributes - ...Object.entries(groupBy(attributeValues, 'attributeKey.name')).reduce( - (acc, [key, values]) => - Object.assign(acc, { - [key]: values.map(({ name }) => name).join(','), - }), - {}, + ...Object.fromEntries( + Object.entries(groupBy(attributeValues, 'attributeKey.name')).map( + ([key, values]) => [key, values.map(({ name }) => name).join(',')], + ), ), }), ); // Write out to CSV - const headers = uniq(data.map((d) => Object.keys(d)).flat()); + const headers = uniq(data.flatMap((d) => Object.keys(d))); writeCsv(file, data, headers); logger.info( diff --git a/src/lib/manual-enrichment/pushManualEnrichmentIdentifiersFromCsv.ts b/src/lib/manual-enrichment/pushManualEnrichmentIdentifiersFromCsv.ts index 9bf33641..58e5f10c 100644 --- a/src/lib/manual-enrichment/pushManualEnrichmentIdentifiersFromCsv.ts +++ b/src/lib/manual-enrichment/pushManualEnrichmentIdentifiersFromCsv.ts @@ -1,18 +1,18 @@ import colors from 'colors'; -import { map } from '../bluebird-replace'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; import { - UPDATE_PRIVACY_REQUEST, buildTranscendGraphQLClient, createSombraGotInstance, makeGraphQLRequest, + UPDATE_PRIVACY_REQUEST, } from '../graphql'; +import { readCsv } from '../requests'; import { enrichPrivacyRequest, EnrichPrivacyRequest, } from './enrichPrivacyRequest'; -import { readCsv } from '../requests'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; /** * Push a CSV of enriched requests back into Transcend @@ -90,7 +90,7 @@ export async function pushManualEnrichmentIdentifiersFromCsv({ } else { skippedCount += 1; } - } catch (err) { + } catch { errorCount += 1; } }, diff --git a/src/lib/mergeTranscendInputs.ts b/src/lib/mergeTranscendInputs.ts index 12084abc..f05ea2a2 100644 --- a/src/lib/mergeTranscendInputs.ts +++ b/src/lib/mergeTranscendInputs.ts @@ -1,5 +1,5 @@ -import { TranscendInput } from '../codecs'; import { getEntries } from '@transcend-io/type-utils'; +import { TranscendInput } from '../codecs'; /** * Combine a set of TranscendInput yaml files into a single yaml @@ -14,7 +14,7 @@ export function mergeTranscendInputs( ): TranscendInput { // eslint-disable-next-line @typescript-eslint/no-explicit-any const cloned: any = JSON.parse(JSON.stringify(base)); - inputs.forEach((input) => { + for (const input of inputs) { // eslint-disable-next-line @typescript-eslint/no-explicit-any getEntries(input).forEach(([key, value]: [any, any]) => { if (cloned[key] === undefined) { @@ -25,6 +25,6 @@ export function mergeTranscendInputs( cloned[key] = value; } }); - }); + } return cloned; } diff --git a/src/lib/oneTrust/endpoints/getListOfOneTrustAssessments.ts b/src/lib/oneTrust/endpoints/getListOfOneTrustAssessments.ts index b2bcbd4a..ef7a9b13 100644 --- a/src/lib/oneTrust/endpoints/getListOfOneTrustAssessments.ts +++ b/src/lib/oneTrust/endpoints/getListOfOneTrustAssessments.ts @@ -1,10 +1,10 @@ -import { Got } from 'got'; -import { logger } from '../../../logger'; -import { decodeCodec } from '@transcend-io/type-utils'; import { OneTrustAssessment, OneTrustGetListOfAssessmentsResponse, } from '@transcend-io/privacy-types'; +import { decodeCodec } from '@transcend-io/type-utils'; +import { Got } from 'got'; +import { logger } from '../../../logger'; /** * Fetch a list of all assessments from the OneTrust client. diff --git a/src/lib/oneTrust/endpoints/getOneTrustAssessment.ts b/src/lib/oneTrust/endpoints/getOneTrustAssessment.ts index 6a02226e..f9440136 100644 --- a/src/lib/oneTrust/endpoints/getOneTrustAssessment.ts +++ b/src/lib/oneTrust/endpoints/getOneTrustAssessment.ts @@ -1,6 +1,6 @@ -import { Got } from 'got'; -import { decodeCodec } from '@transcend-io/type-utils'; import { OneTrustGetAssessmentResponse } from '@transcend-io/privacy-types'; +import { decodeCodec } from '@transcend-io/type-utils'; +import { Got } from 'got'; /** * Retrieve details about a particular assessment. diff --git a/src/lib/oneTrust/endpoints/getOneTrustRisk.ts b/src/lib/oneTrust/endpoints/getOneTrustRisk.ts index 78184b02..fa1d392e 100644 --- a/src/lib/oneTrust/endpoints/getOneTrustRisk.ts +++ b/src/lib/oneTrust/endpoints/getOneTrustRisk.ts @@ -1,6 +1,6 @@ -import { Got } from 'got'; -import { decodeCodec } from '@transcend-io/type-utils'; import { OneTrustGetRiskResponse } from '@transcend-io/privacy-types'; +import { decodeCodec } from '@transcend-io/type-utils'; +import { Got } from 'got'; /** * Retrieve details about a particular risk. diff --git a/src/lib/oneTrust/endpoints/getOneTrustUser.ts b/src/lib/oneTrust/endpoints/getOneTrustUser.ts index edbf81da..a2fa931c 100644 --- a/src/lib/oneTrust/endpoints/getOneTrustUser.ts +++ b/src/lib/oneTrust/endpoints/getOneTrustUser.ts @@ -1,6 +1,6 @@ -import { Got } from 'got'; -import { decodeCodec } from '@transcend-io/type-utils'; import { OneTrustGetUserResponse } from '@transcend-io/privacy-types'; +import { decodeCodec } from '@transcend-io/type-utils'; +import { Got } from 'got'; /** * Retrieve details about a particular user. diff --git a/src/lib/oneTrust/helpers/convertToEmptyStrings.ts b/src/lib/oneTrust/helpers/convertToEmptyStrings.ts index 24757d82..067e325a 100644 --- a/src/lib/oneTrust/helpers/convertToEmptyStrings.ts +++ b/src/lib/oneTrust/helpers/convertToEmptyStrings.ts @@ -46,12 +46,11 @@ export function convertToEmptyStrings(input: T): any { // Handle objects if (typeof input === 'object') { - return Object.entries(input).reduce( - (acc, [key, value]) => ({ - ...acc, - [key]: convertToEmptyStrings(value), - }), - {} as Record, + return Object.fromEntries( + Object.entries(input).map>(([key, value]) => [ + key, + convertToEmptyStrings(value), + ]), ); } diff --git a/src/lib/oneTrust/helpers/parseCliSyncOtArguments.ts b/src/lib/oneTrust/helpers/parseCliSyncOtArguments.ts index 640ffb5a..5dde3ee2 100644 --- a/src/lib/oneTrust/helpers/parseCliSyncOtArguments.ts +++ b/src/lib/oneTrust/helpers/parseCliSyncOtArguments.ts @@ -1,4 +1,3 @@ -import { logger } from '../../../logger'; import colors from 'colors'; import yargs from 'yargs-parser'; import { @@ -6,6 +5,7 @@ import { OneTrustPullResource, OneTrustPullSource, } from '../../../enums'; +import { logger } from '../../../logger'; const VALID_RESOURCES = Object.values(OneTrustPullResource); @@ -71,7 +71,6 @@ export const parseCliSyncOtArguments = (): OneTrustCliArguments => { if (!dryRun && !transcendAuth) { logger.error( colors.red( - // eslint-disable-next-line no-template-curly-in-string 'Must specify a "transcendAuth" parameter to sync resources to Transcend. e.g. --transcendAuth=${TRANSCEND_API_KEY}', ), ); @@ -80,7 +79,6 @@ export const parseCliSyncOtArguments = (): OneTrustCliArguments => { if (!dryRun && !transcendUrl) { logger.error( colors.red( - // eslint-disable-next-line max-len 'Must specify a "transcendUrl" parameter to sync resources to Transcend. e.g. --transcendUrl=https://api.transcend.io', ), ); diff --git a/src/lib/oneTrust/helpers/syncOneTrustAssessmentToDisk.ts b/src/lib/oneTrust/helpers/syncOneTrustAssessmentToDisk.ts index 1a00c7c0..ee2a9126 100644 --- a/src/lib/oneTrust/helpers/syncOneTrustAssessmentToDisk.ts +++ b/src/lib/oneTrust/helpers/syncOneTrustAssessmentToDisk.ts @@ -1,8 +1,8 @@ -import { logger } from '../../../logger'; +import fs from 'node:fs'; +import { OneTrustEnrichedAssessment } from '@transcend-io/privacy-types'; import colors from 'colors'; -import fs from 'fs'; +import { logger } from '../../../logger'; import { oneTrustAssessmentToJson } from './oneTrustAssessmentToJson'; -import { OneTrustEnrichedAssessment } from '@transcend-io/privacy-types'; /** * Write the assessment to disk at the specified file path. diff --git a/src/lib/oneTrust/helpers/syncOneTrustAssessmentToTranscend.ts b/src/lib/oneTrust/helpers/syncOneTrustAssessmentToTranscend.ts index 4026ad18..e18c1d26 100644 --- a/src/lib/oneTrust/helpers/syncOneTrustAssessmentToTranscend.ts +++ b/src/lib/oneTrust/helpers/syncOneTrustAssessmentToTranscend.ts @@ -1,12 +1,12 @@ -import { logger } from '../../../logger'; +import { OneTrustEnrichedAssessment } from '@transcend-io/privacy-types'; import colors from 'colors'; import { GraphQLClient } from 'graphql-request'; +import { ImportOnetrustAssessmentsInput } from '../../../codecs'; +import { logger } from '../../../logger'; import { IMPORT_ONE_TRUST_ASSESSMENT_FORMS, makeGraphQLRequest, } from '../../graphql'; -import { ImportOnetrustAssessmentsInput } from '../../../codecs'; -import { OneTrustEnrichedAssessment } from '@transcend-io/privacy-types'; import { oneTrustAssessmentToJson } from './oneTrustAssessmentToJson'; export interface AssessmentForm { @@ -67,7 +67,7 @@ export const syncOneTrustAssessmentToTranscend = async ({ }>(transcend, IMPORT_ONE_TRUST_ASSESSMENT_FORMS, { input, }); - } catch (e) { + } catch { logger.error( colors.red( `Failed to sync assessment ${index + 1} ${ diff --git a/src/lib/oneTrust/helpers/syncOneTrustAssessmentsFromFile.ts b/src/lib/oneTrust/helpers/syncOneTrustAssessmentsFromFile.ts index 1783eb00..e2d3ae23 100644 --- a/src/lib/oneTrust/helpers/syncOneTrustAssessmentsFromFile.ts +++ b/src/lib/oneTrust/helpers/syncOneTrustAssessmentsFromFile.ts @@ -1,12 +1,11 @@ +import { createReadStream } from 'node:fs'; +import { OneTrustEnrichedAssessment } from '@transcend-io/privacy-types'; import { decodeCodec } from '@transcend-io/type-utils'; import colors from 'colors'; -import { logger } from '../../../logger'; +import { GraphQLClient } from 'graphql-request'; import JSONStream from 'JSONStream'; - -import { createReadStream } from 'fs'; -import { OneTrustEnrichedAssessment } from '@transcend-io/privacy-types'; +import { logger } from '../../../logger'; import { syncOneTrustAssessmentToTranscend } from './syncOneTrustAssessmentToTranscend'; -import { GraphQLClient } from 'graphql-request'; /** * Reads assessments from a file and syncs them to Transcend. @@ -62,11 +61,11 @@ export const syncOneTrustAssessmentsFromFile = ({ // Resume the stream after processing parser.resume(); - } catch (e) { + } catch (error) { // if failed to parse a line, report error and continue logger.error( colors.red( - `Failed to parse the assessment ${index} from file '${file}': ${e.message}.`, + `Failed to parse the assessment ${index} from file '${file}': ${error.message}.`, ), ); } diff --git a/src/lib/oneTrust/helpers/syncOneTrustAssessmentsFromOneTrust.ts b/src/lib/oneTrust/helpers/syncOneTrustAssessmentsFromOneTrust.ts index 6792c963..c06eb645 100644 --- a/src/lib/oneTrust/helpers/syncOneTrustAssessmentsFromOneTrust.ts +++ b/src/lib/oneTrust/helpers/syncOneTrustAssessmentsFromOneTrust.ts @@ -1,13 +1,3 @@ -import type { Got } from 'got'; -import colors from 'colors'; -import { - getListOfOneTrustAssessments, - getOneTrustAssessment, - getOneTrustRisk, - getOneTrustUser, -} from '../endpoints'; -import { mapSeries, map } from '../../bluebird-replace'; -import { logger } from '../../../logger'; import { OneTrustAssessmentQuestion, OneTrustAssessmentSection, @@ -15,10 +5,20 @@ import { OneTrustGetRiskResponse, OneTrustGetUserResponse, } from '@transcend-io/privacy-types'; +import colors from 'colors'; +import type { Got } from 'got'; +import { GraphQLClient } from 'graphql-request'; import { uniq } from 'lodash-es'; +import { logger } from '../../../logger'; +import { map, mapSeries } from '../../bluebird-replace'; +import { + getListOfOneTrustAssessments, + getOneTrustAssessment, + getOneTrustRisk, + getOneTrustUser, +} from '../endpoints'; import { enrichOneTrustAssessment } from './enrichOneTrustAssessment'; import { syncOneTrustAssessmentToDisk } from './syncOneTrustAssessmentToDisk'; -import { GraphQLClient } from 'graphql-request'; import { syncOneTrustAssessmentToTranscend } from './syncOneTrustAssessmentToTranscend'; export interface AssessmentForm { @@ -61,7 +61,8 @@ export const syncOneTrustAssessmentsFromOneTrust = async ({ { length: Math.ceil(assessments.length / BATCH_SIZE), }, - (_, i) => assessments.slice(i * BATCH_SIZE, (i + 1) * BATCH_SIZE), + (_, index) => + assessments.slice(index * BATCH_SIZE, (index + 1) * BATCH_SIZE), ); // process each batch and sync the batch right away so it's garbage collected and we don't run out of memory @@ -94,7 +95,7 @@ export const syncOneTrustAssessmentsFromOneTrust = async ({ userId: creatorId, }); oneTrustCachedUsers[creatorId] = creator; - } catch (e) { + } catch { logger.warn( colors.yellow( `[assessment ${assessmentNumber} of ${assessments.length}]: failed to fetch form creator.` + @@ -121,7 +122,7 @@ export const syncOneTrustAssessmentsFromOneTrust = async ({ oneTrustCachedUsers[userId] = approver; } return [approver]; - } catch (e) { + } catch { logger.warn( colors.yellow( `[assessment ${assessmentNumber} of ${assessments.length}]: failed to fetch a form approver.` + @@ -156,7 +157,7 @@ export const syncOneTrustAssessmentsFromOneTrust = async ({ oneTrustCachedUsers[userId] = respondent; } return [respondent]; - } catch (e) { + } catch { logger.warn( colors.yellow( `[assessment ${assessmentNumber} of ${assessments.length}]: failed to fetch a respondent.` + @@ -185,7 +186,7 @@ export const syncOneTrustAssessmentsFromOneTrust = async ({ ); riskDetails = await map( riskIds, - (riskId) => getOneTrustRisk({ oneTrust, riskId: riskId as string }), + (riskId) => getOneTrustRisk({ oneTrust, riskId: riskId }), { concurrency: 5, }, diff --git a/src/lib/oneTrust/helpers/tests/convertToEmptyStrings.test.ts b/src/lib/oneTrust/helpers/tests/convertToEmptyStrings.test.ts index 69269172..a5de0dd5 100644 --- a/src/lib/oneTrust/helpers/tests/convertToEmptyStrings.test.ts +++ b/src/lib/oneTrust/helpers/tests/convertToEmptyStrings.test.ts @@ -1,5 +1,4 @@ -import { expect, describe, it } from 'vitest'; - +import { describe, expect, it } from 'vitest'; import { convertToEmptyStrings } from '../convertToEmptyStrings'; describe('buildDefaultCodecWrapper', () => { @@ -19,7 +18,7 @@ describe('buildDefaultCodecWrapper', () => { }); it('should correctly build a default codec for undefined', () => { - const result = convertToEmptyStrings(undefined); + const result = convertToEmptyStrings(); expect(result).to.equal(''); }); diff --git a/src/lib/preference-management/checkIfPendingPreferenceUpdatesAreNoOp.ts b/src/lib/preference-management/checkIfPendingPreferenceUpdatesAreNoOp.ts index 17b5525c..e9e464a3 100644 --- a/src/lib/preference-management/checkIfPendingPreferenceUpdatesAreNoOp.ts +++ b/src/lib/preference-management/checkIfPendingPreferenceUpdatesAreNoOp.ts @@ -19,9 +19,10 @@ export function checkIfPendingPreferenceUpdatesAreNoOp({ /** The current consent record */ currentConsentRecord: PreferenceQueryResponseItem; /** The pending updates */ - pendingUpdates: { - [purposeName in string]: Omit; - }; + pendingUpdates: Record< + string, + Omit + >; /** The preference topic configurations */ preferenceTopics: PreferenceTopic[]; }): boolean { @@ -42,51 +43,54 @@ export function checkIfPendingPreferenceUpdatesAreNoOp({ } // Compare the preferences are in sync - return preferences.every( - ({ topic, choice }) => - // ensure preferences exist on record - currentPurpose.preferences && - currentPurpose.preferences.find((existingPreference) => { - // find matching topic - if (existingPreference.topic !== topic) { - return false; - } + return preferences.every(({ topic, choice }) => + // ensure preferences exist on record + currentPurpose.preferences?.find((existingPreference) => { + // find matching topic + if (existingPreference.topic !== topic) { + return false; + } + + // Determine type of preference topic + const preferenceTopic = preferenceTopics.find( + (x) => x.slug === topic && x.purpose.trackingType === purposeName, + ); + if (!preferenceTopic) { + throw new Error(`Could not find preference topic for ${topic}`); + } - // Determine type of preference topic - const preferenceTopic = preferenceTopics.find( - (x) => x.slug === topic && x.purpose.trackingType === purposeName, - ); - if (!preferenceTopic) { - throw new Error(`Could not find preference topic for ${topic}`); + // Handle comparison based on type + switch (preferenceTopic.type) { + case PreferenceTopicType.Boolean: { + return ( + existingPreference.choice.booleanValue === choice.booleanValue + ); } + case PreferenceTopicType.Select: { + return ( + existingPreference.choice.selectValue === choice.selectValue + ); + } + case PreferenceTopicType.MultiSelect: { + const sortedCurrentValues = ( + existingPreference.choice.selectValues || [] + ).sort(); - // Handle comparison based on type - switch (preferenceTopic.type) { - case PreferenceTopicType.Boolean: - return ( - existingPreference.choice.booleanValue === choice.booleanValue - ); - case PreferenceTopicType.Select: - return ( - existingPreference.choice.selectValue === choice.selectValue - ); - case PreferenceTopicType.MultiSelect: - // eslint-disable-next-line no-case-declarations - const sortedCurrentValues = ( - existingPreference.choice.selectValues || [] - ).sort(); - // eslint-disable-next-line no-case-declarations - const sortedNewValues = (choice.selectValues || []).sort(); - return ( - sortedCurrentValues.length === sortedNewValues.length && - sortedCurrentValues.every((x, i) => x === sortedNewValues[i]) - ); - default: - throw new Error( - `Unknown preference topic type: ${preferenceTopic.type}`, - ); + const sortedNewValues = (choice.selectValues || []).sort(); + return ( + sortedCurrentValues.length === sortedNewValues.length && + sortedCurrentValues.every( + (x, index) => x === sortedNewValues[index], + ) + ); + } + default: { + throw new Error( + `Unknown preference topic type: ${preferenceTopic.type}`, + ); } - }), + } + }), ); }, ); diff --git a/src/lib/preference-management/checkIfPendingPreferenceUpdatesCauseConflict.ts b/src/lib/preference-management/checkIfPendingPreferenceUpdatesCauseConflict.ts index a14b4845..276d170f 100644 --- a/src/lib/preference-management/checkIfPendingPreferenceUpdatesCauseConflict.ts +++ b/src/lib/preference-management/checkIfPendingPreferenceUpdatesCauseConflict.ts @@ -20,9 +20,10 @@ export function checkIfPendingPreferenceUpdatesCauseConflict({ /** The current consent record */ currentConsentRecord: PreferenceQueryResponseItem; /** The pending updates */ - pendingUpdates: { - [purposeName in string]: Omit; - }; + pendingUpdates: Record< + string, + Omit + >; /** The preference topic configurations */ preferenceTopics: PreferenceTopic[]; }): boolean { @@ -66,27 +67,32 @@ export function checkIfPendingPreferenceUpdatesCauseConflict({ // Handle comparison based on type switch (preferenceTopic.type) { - case PreferenceTopicType.Boolean: + case PreferenceTopicType.Boolean: { return ( currentPreference.choice.booleanValue !== choice.booleanValue ); - case PreferenceTopicType.Select: + } + case PreferenceTopicType.Select: { return currentPreference.choice.selectValue !== choice.selectValue; - case PreferenceTopicType.MultiSelect: - // eslint-disable-next-line no-case-declarations + } + case PreferenceTopicType.MultiSelect: { const sortedCurrentValues = ( currentPreference.choice.selectValues || [] ).sort(); - // eslint-disable-next-line no-case-declarations + const sortedNewValues = (choice.selectValues || []).sort(); return ( sortedCurrentValues.length !== sortedNewValues.length || - !sortedCurrentValues.every((x, i) => x === sortedNewValues[i]) + !sortedCurrentValues.every( + (x, index) => x === sortedNewValues[index], + ) ); - default: + } + default: { throw new Error( `Unknown preference topic type: ${preferenceTopic.type}`, ); + } } }); }, diff --git a/src/lib/preference-management/getPreferenceUpdatesFromRow.ts b/src/lib/preference-management/getPreferenceUpdatesFromRow.ts index 32d63f68..da4b3ac3 100644 --- a/src/lib/preference-management/getPreferenceUpdatesFromRow.ts +++ b/src/lib/preference-management/getPreferenceUpdatesFromRow.ts @@ -2,10 +2,10 @@ import { PreferenceStorePurposeResponse, PreferenceTopicType, } from '@transcend-io/privacy-types'; -import { PurposeRowMapping } from './codecs'; import { apply } from '@transcend-io/type-utils'; import { PreferenceTopic } from '../graphql'; import { splitCsvToList } from '../requests'; +import { PurposeRowMapping } from './codecs'; /** * Parse an arbitrary object to the Transcend PUT /v1/preference update shape @@ -42,155 +42,154 @@ export function getPreferenceUpdatesFromRow({ purposeSlugs: string[]; /** The preference topics */ preferenceTopics: PreferenceTopic[]; -}): { - [k in string]: Omit; -} { +}): Record> { // Create a result object to store the parsed preferences - const result: { - [k in string]: Partial; - } = {}; + const result: Record> = {}; // Iterate over each column and map to the purpose or preference - Object.entries(columnToPurposeName).forEach( - ([columnName, { purpose, preference, valueMapping }]) => { - // Ensure the purpose is valid - if (!purposeSlugs.includes(purpose)) { + for (const [ + columnName, + { purpose, preference, valueMapping }, + ] of Object.entries(columnToPurposeName)) { + // Ensure the purpose is valid + if (!purposeSlugs.includes(purpose)) { + throw new Error( + `Invalid purpose slug: ${purpose}, expected: ${purposeSlugs.join(', ')}`, + ); + } + + // CHeck if parsing a preference or just the top level purpose + if (preference) { + const preferenceTopic = preferenceTopics.find( + (x) => x.slug === preference && x.purpose.trackingType === purpose, + ); + if (!preferenceTopic) { + const allowedTopics = preferenceTopics + .filter((x) => x.purpose.trackingType === purpose) + .map((x) => x.slug); throw new Error( - `Invalid purpose slug: ${purpose}, expected: ${purposeSlugs.join( - ', ', - )}`, + `Invalid preference slug: ${preference} for purpose: ${purpose}. ` + + `Allowed preference slugs for purpose are: ${allowedTopics.join( + ',', + )}`, ); } - // CHeck if parsing a preference or just the top level purpose - if (preference) { - const preferenceTopic = preferenceTopics.find( - (x) => x.slug === preference && x.purpose.trackingType === purpose, - ); - if (!preferenceTopic) { - const allowedTopics = preferenceTopics - .filter((x) => x.purpose.trackingType === purpose) - .map((x) => x.slug); - throw new Error( - `Invalid preference slug: ${preference} for purpose: ${purpose}. ` + - `Allowed preference slugs for purpose are: ${allowedTopics.join( - ',', - )}`, - ); - } - - // If parsing preferences, default to an empty array - if (!result[purpose]) { - result[purpose] = { - preferences: [], - }; - } - if (!result[purpose].preferences) { - result[purpose].preferences = []; - } + // If parsing preferences, default to an empty array + if (!result[purpose]) { + result[purpose] = { + preferences: [], + }; + } + if (!result[purpose].preferences) { + result[purpose].preferences = []; + } - // The value to parse - const rawValue = row[columnName]; - const rawMapping = valueMapping[rawValue]; - const trimmedMapping = - typeof rawMapping === 'string' ? rawMapping.trim() || null : null; + // The value to parse + const rawValue = row[columnName]; + const rawMapping = valueMapping[rawValue]; + const trimmedMapping = + typeof rawMapping === 'string' ? rawMapping.trim() || null : null; - // handle each type of preference - switch (preferenceTopic.type) { - case PreferenceTopicType.Boolean: - if (typeof rawMapping !== 'boolean') { - throw new Error( - `Invalid value for boolean preference: ${preference}, expected boolean, got: ${rawValue}`, - ); - } - result[purpose].preferences!.push({ - topic: preference, - choice: { - booleanValue: rawMapping, - }, - }); - break; - case PreferenceTopicType.Select: - if (typeof rawMapping !== 'string' && rawMapping !== null) { - throw new Error( - `Invalid value for select preference: ${preference}, expected string or null, got: ${rawValue}`, - ); - } + // handle each type of preference + switch (preferenceTopic.type) { + case PreferenceTopicType.Boolean: { + if (typeof rawMapping !== 'boolean') { + throw new TypeError( + `Invalid value for boolean preference: ${preference}, expected boolean, got: ${rawValue}`, + ); + } + result[purpose].preferences.push({ + topic: preference, + choice: { + booleanValue: rawMapping, + }, + }); + break; + } + case PreferenceTopicType.Select: { + if (typeof rawMapping !== 'string' && rawMapping !== null) { + throw new Error( + `Invalid value for select preference: ${preference}, expected string or null, got: ${rawValue}`, + ); + } - if ( - trimmedMapping && - !preferenceTopic.preferenceOptionValues - .map(({ slug }) => slug) - .includes(trimmedMapping) - ) { - throw new Error( - `Invalid value for select preference: ${preference}, expected one of: ` + - `${preferenceTopic.preferenceOptionValues - .map(({ slug }) => slug) - .join(', ')}, got: ${rawValue}`, - ); - } + if ( + trimmedMapping && + !preferenceTopic.preferenceOptionValues + .map(({ slug }) => slug) + .includes(trimmedMapping) + ) { + throw new Error( + `Invalid value for select preference: ${preference}, expected one of: ` + + `${preferenceTopic.preferenceOptionValues + .map(({ slug }) => slug) + .join(', ')}, got: ${rawValue}`, + ); + } - // Update preferences - result[purpose].preferences!.push({ - topic: preference, - choice: { - selectValue: trimmedMapping, - }, - }); - break; - case PreferenceTopicType.MultiSelect: - if (typeof rawValue !== 'string') { - throw new Error( - `Invalid value for multi select preference: ${preference}, expected string, got: ${rawValue}`, - ); - } - // Update preferences - result[purpose].preferences!.push({ - topic: preference, - choice: { - selectValues: splitCsvToList(rawValue) - .map((val) => { - const result = valueMapping[val]; - if (typeof result !== 'string') { - throw new Error( - `Invalid value for multi select preference: ${preference}, ` + - `expected one of: ${preferenceTopic.preferenceOptionValues - .map(({ slug }) => slug) - .join(', ')}, got: ${val}`, - ); - } - return result; - }) - .sort((a, b) => a.localeCompare(b)), - }, - }); - break; - default: - throw new Error(`Unknown preference type: ${preferenceTopic.type}`); + // Update preferences + result[purpose].preferences.push({ + topic: preference, + choice: { + selectValue: trimmedMapping, + }, + }); + break; + } + case PreferenceTopicType.MultiSelect: { + if (typeof rawValue !== 'string') { + throw new TypeError( + `Invalid value for multi select preference: ${preference}, expected string, got: ${rawValue}`, + ); + } + // Update preferences + result[purpose].preferences.push({ + topic: preference, + choice: { + selectValues: splitCsvToList(rawValue) + .map((value) => { + const result = valueMapping[value]; + if (typeof result !== 'string') { + throw new TypeError( + `Invalid value for multi select preference: ${preference}, ` + + `expected one of: ${preferenceTopic.preferenceOptionValues + .map(({ slug }) => slug) + .join(', ')}, got: ${value}`, + ); + } + return result; + }) + .sort((a, b) => a.localeCompare(b)), + }, + }); + break; + } + default: { + throw new Error(`Unknown preference type: ${preferenceTopic.type}`); } - } else if (!result[purpose]) { - // Handle updating top level purpose for the first time - result[purpose] = { - enabled: valueMapping[row[columnName]] === true, - }; - } else { - // Handle updating top level purpose but preserve preference updates - result[purpose].enabled = valueMapping[row[columnName]] === true; } - }, - ); + } else if (result[purpose]) { + // Handle updating top level purpose but preserve preference updates + result[purpose].enabled = valueMapping[row[columnName]] === true; + } else { + // Handle updating top level purpose for the first time + result[purpose] = { + enabled: valueMapping[row[columnName]] === true, + }; + } + } // Ensure that enabled is provided return apply(result, (x, purposeName) => { if (typeof x.enabled !== 'boolean') { - throw new Error( + throw new TypeError( `No mapping provided for purpose.enabled=true/false value: ${purposeName}`, ); } return { ...x, - enabled: x.enabled!, + enabled: x.enabled, }; }); } diff --git a/src/lib/preference-management/getPreferencesForIdentifiers.ts b/src/lib/preference-management/getPreferencesForIdentifiers.ts index 6a77d9b8..5fd84c25 100644 --- a/src/lib/preference-management/getPreferencesForIdentifiers.ts +++ b/src/lib/preference-management/getPreferencesForIdentifiers.ts @@ -1,12 +1,12 @@ import { PreferenceQueryResponseItem } from '@transcend-io/privacy-types'; -import type { Got } from 'got'; -import colors from 'colors'; -import cliProgress from 'cli-progress'; -import { chunk } from 'lodash-es'; import { decodeCodec } from '@transcend-io/type-utils'; +import cliProgress from 'cli-progress'; +import colors from 'colors'; +import type { Got } from 'got'; import * as t from 'io-ts'; -import { map } from '../bluebird-replace'; +import { chunk } from 'lodash-es'; import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; const PreferenceRecordsQueryResponse = t.intersection([ t.type({ @@ -54,7 +54,7 @@ export async function getPreferencesForIdentifiers( const groupedIdentifiers = chunk(identifiers, 100); // create a new progress bar instance and use shades_classic theme - const t0 = new Date().getTime(); + const t0 = Date.now(); const progressBar = new cliProgress.SingleBar( {}, cliProgress.Presets.shades_classic, @@ -88,22 +88,22 @@ export async function getPreferencesForIdentifiers( total += group.length; progressBar.update(total); break; // Exit loop if successful - } catch (err) { + } catch (error) { attempts += 1; - const msg = err?.response?.body || err?.message || ''; + const message = error?.response?.body || error?.message || ''; if ( attempts >= maxAttempts || - !MSGS.some((errorMessage) => msg.includes(errorMessage)) + !MSGS.some((errorMessage) => message.includes(errorMessage)) ) { throw new Error( - `Received an error from server after ${attempts} attempts: ${msg}`, + `Received an error from server after ${attempts} attempts: ${message}`, ); } logger.warn( colors.yellow( `[RETRYING FAILED REQUEST - Attempt ${attempts}] ` + - `Failed to fetch ${group.length} user preferences from partition ${partitionKey}: ${msg}`, + `Failed to fetch ${group.length} user preferences from partition ${partitionKey}: ${message}`, ), ); } @@ -115,7 +115,7 @@ export async function getPreferencesForIdentifiers( ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; if (!skipLogging) { diff --git a/src/lib/preference-management/parsePreferenceAndPurposeValuesFromCsv.ts b/src/lib/preference-management/parsePreferenceAndPurposeValuesFromCsv.ts index 7c81c206..c0845f58 100644 --- a/src/lib/preference-management/parsePreferenceAndPurposeValuesFromCsv.ts +++ b/src/lib/preference-management/parsePreferenceAndPurposeValuesFromCsv.ts @@ -1,14 +1,12 @@ -import { uniq, difference } from 'lodash-es'; +import { PreferenceTopicType } from '@transcend-io/privacy-types'; import colors from 'colors'; import inquirer from 'inquirer'; -import { FileMetadataState } from './codecs'; +import { difference, uniq } from 'lodash-es'; import { logger } from '../../logger'; import { mapSeries } from '../bluebird-replace'; import { PreferenceTopic } from '../graphql'; -import { PreferenceTopicType } from '@transcend-io/privacy-types'; import { splitCsvToList } from '../requests'; - -/* eslint-disable no-param-reassign */ +import { FileMetadataState } from './codecs'; /** * Parse out the purpose.enabled and preference values from a CSV file @@ -35,7 +33,7 @@ export async function parsePreferenceAndPurposeValuesFromCsv( }, ): Promise { // Determine columns to map - const columnNames = uniq(preferences.map((x) => Object.keys(x)).flat()); + const columnNames = uniq(preferences.flatMap((x) => Object.keys(x))); // Determine the columns that could potentially be used for identifier const otherColumns = difference(columnNames, [ @@ -139,9 +137,7 @@ export async function parsePreferenceAndPurposeValuesFromCsv( }>([ { name: 'preferenceValue', - message: - // eslint-disable-next-line max-len - `Choose the preference value for "${preferenceTopic.slug}" value "${value}" associated with purpose "${purposeMapping.purpose}"`, + message: `Choose the preference value for "${preferenceTopic.slug}" value "${value}" associated with purpose "${purposeMapping.purpose}"`, type: 'confirm', default: value !== 'false', }, @@ -157,7 +153,7 @@ export async function parsePreferenceAndPurposeValuesFromCsv( }>([ { name: 'preferenceValue', - // eslint-disable-next-line max-len + message: `Choose the preference value for "${preferenceTopic.slug}" value "${value}" associated with purpose "${purposeMapping.purpose}"`, type: 'list', choices: preferenceOptions, @@ -182,7 +178,7 @@ export async function parsePreferenceAndPurposeValuesFromCsv( }>([ { name: 'preferenceValue', - // eslint-disable-next-line max-len + message: `Choose the preference value for "${preferenceTopic.slug}" value "${parsedValue}" associated with purpose "${purposeMapping.purpose}"`, type: 'list', choices: preferenceOptions, @@ -205,4 +201,3 @@ export async function parsePreferenceAndPurposeValuesFromCsv( return currentState; } -/* eslint-enable no-param-reassign */ diff --git a/src/lib/preference-management/parsePreferenceIdentifiersFromCsv.ts b/src/lib/preference-management/parsePreferenceIdentifiersFromCsv.ts index 0c65ccf2..df9357ce 100644 --- a/src/lib/preference-management/parsePreferenceIdentifiersFromCsv.ts +++ b/src/lib/preference-management/parsePreferenceIdentifiersFromCsv.ts @@ -1,11 +1,9 @@ -import { uniq, groupBy, difference } from 'lodash-es'; import colors from 'colors'; import inquirer from 'inquirer'; -import { FileMetadataState } from './codecs'; +import { difference, groupBy, uniq } from 'lodash-es'; import { logger } from '../../logger'; import { inquirerConfirmBoolean } from '../helpers'; - -/* eslint-disable no-param-reassign */ +import { FileMetadataState } from './codecs'; /** * Parse identifiers from a CSV list of preferences @@ -27,7 +25,7 @@ export async function parsePreferenceIdentifiersFromCsv( preferences: Record[]; }> { // Determine columns to map - const columnNames = uniq(preferences.map((x) => Object.keys(x)).flat()); + const columnNames = uniq(preferences.flatMap((x) => Object.keys(x))); // Determine the columns that could potentially be used for identifier const remainingColumnsForIdentifier = difference(columnNames, [ @@ -67,19 +65,19 @@ export async function parsePreferenceIdentifiersFromCsv( .filter((x): x is number[] => !!x) .flat(); if (identifierColumnsMissing.length > 0) { - const msg = `The identifier column "${ + const message = `The identifier column "${ currentState.identifierColumn }" is missing a value for the following rows: ${identifierColumnsMissing.join( ', ', )}`; - logger.warn(colors.yellow(msg)); + logger.warn(colors.yellow(message)); // Ask user if they would like to skip rows missing an identifier const skip = await inquirerConfirmBoolean({ message: 'Would you like to skip rows missing an identifier?', }); if (!skip) { - throw new Error(msg); + throw new Error(message); } // Filter out rows missing an identifier @@ -105,13 +103,13 @@ export async function parsePreferenceIdentifiersFromCsv( ([, rows]) => rows.length > 1, ); if (duplicateIdentifiers.length > 0) { - const msg = `The identifier column "${ + const message = `The identifier column "${ currentState.identifierColumn }" has duplicate values for the following rows: ${duplicateIdentifiers .slice(0, 10) .map(([userId, rows]) => `${userId} (${rows.length})`) .join('\n')}`; - logger.warn(colors.yellow(msg)); + logger.warn(colors.yellow(message)); // Ask user if they would like to take the most recent update // for each duplicate identifier @@ -119,7 +117,7 @@ export async function parsePreferenceIdentifiersFromCsv( message: 'Would you like to automatically take the latest update?', }); if (!skip) { - throw new Error(msg); + throw new Error(message); } preferences = Object.entries(rowsByUserId) .map(([, rows]) => { @@ -130,9 +128,8 @@ export async function parsePreferenceIdentifiersFromCsv( ); return sorted[0]; }) - .filter((x) => x); + .filter(Boolean); } return { currentState, preferences }; } -/* eslint-enable no-param-reassign */ diff --git a/src/lib/preference-management/parsePreferenceManagementCsv.ts b/src/lib/preference-management/parsePreferenceManagementCsv.ts index 10b36831..c0d629f5 100644 --- a/src/lib/preference-management/parsePreferenceManagementCsv.ts +++ b/src/lib/preference-management/parsePreferenceManagementCsv.ts @@ -1,19 +1,19 @@ import { PersistedState } from '@transcend-io/persisted-state'; +import colors from 'colors'; import type { Got } from 'got'; -import { keyBy } from 'lodash-es'; import * as t from 'io-ts'; -import colors from 'colors'; -import { FileMetadataState, PreferenceState } from './codecs'; +import { keyBy } from 'lodash-es'; import { logger } from '../../logger'; +import { PreferenceTopic } from '../graphql'; import { readCsv } from '../requests'; +import { checkIfPendingPreferenceUpdatesAreNoOp } from './checkIfPendingPreferenceUpdatesAreNoOp'; +import { checkIfPendingPreferenceUpdatesCauseConflict } from './checkIfPendingPreferenceUpdatesCauseConflict'; +import { FileMetadataState, PreferenceState } from './codecs'; import { getPreferencesForIdentifiers } from './getPreferencesForIdentifiers'; -import { PreferenceTopic } from '../graphql'; import { getPreferenceUpdatesFromRow } from './getPreferenceUpdatesFromRow'; -import { parsePreferenceTimestampsFromCsv } from './parsePreferenceTimestampsFromCsv'; -import { parsePreferenceIdentifiersFromCsv } from './parsePreferenceIdentifiersFromCsv'; import { parsePreferenceAndPurposeValuesFromCsv } from './parsePreferenceAndPurposeValuesFromCsv'; -import { checkIfPendingPreferenceUpdatesAreNoOp } from './checkIfPendingPreferenceUpdatesAreNoOp'; -import { checkIfPendingPreferenceUpdatesCauseConflict } from './checkIfPendingPreferenceUpdatesCauseConflict'; +import { parsePreferenceIdentifiersFromCsv } from './parsePreferenceIdentifiersFromCsv'; +import { parsePreferenceTimestampsFromCsv } from './parsePreferenceTimestampsFromCsv'; /** * Parse a file into the cache @@ -51,7 +51,7 @@ export async function parsePreferenceManagementCsvWithCache( cache: PersistedState, ): Promise { // Start the timer - const t0 = new Date().getTime(); + const t0 = Date.now(); // Get the current metadata const fileMetadata = cache.getValue('fileMetadata'); @@ -121,7 +121,7 @@ export async function parsePreferenceManagementCsvWithCache( currentState.skippedUpdates = {}; // Process each row - preferences.forEach((pref) => { + for (const pref of preferences) { // Grab unique Id for the user const userId = pref[currentState.identifierColumn!]; @@ -154,7 +154,7 @@ export async function parsePreferenceManagementCsvWithCache( !forceTriggerWorkflows ) { currentState.skippedUpdates[userId] = pref; - return; + continue; } // Determine if there are any conflicts @@ -170,17 +170,17 @@ export async function parsePreferenceManagementCsvWithCache( row: pref, record: currentConsentRecord, }; - return; + continue; } // Add to pending updates currentState.pendingSafeUpdates[userId] = pref; - }); + } // Read in the file fileMetadata[file] = currentState; await cache.setValue(fileMetadata, 'fileMetadata'); - const t1 = new Date().getTime(); + const t1 = Date.now(); logger.info( colors.green( `Successfully pre-processed file: "${file}" in ${(t1 - t0) / 1000}s`, diff --git a/src/lib/preference-management/parsePreferenceTimestampsFromCsv.ts b/src/lib/preference-management/parsePreferenceTimestampsFromCsv.ts index 6df3ac05..09b2fb48 100644 --- a/src/lib/preference-management/parsePreferenceTimestampsFromCsv.ts +++ b/src/lib/preference-management/parsePreferenceTimestampsFromCsv.ts @@ -1,13 +1,11 @@ -import { uniq, difference } from 'lodash-es'; import colors from 'colors'; import inquirer from 'inquirer'; -import { FileMetadataState } from './codecs'; +import { difference, uniq } from 'lodash-es'; import { logger } from '../../logger'; +import { FileMetadataState } from './codecs'; export const NONE_PREFERENCE_MAP = '[NONE]'; -/* eslint-disable no-param-reassign */ - /** * Parse timestamps from a CSV list of preferences * @@ -25,7 +23,7 @@ export async function parsePreferenceTimestampsFromCsv( currentState: FileMetadataState, ): Promise { // Determine columns to map - const columnNames = uniq(preferences.map((x) => Object.keys(x)).flat()); + const columnNames = uniq(preferences.flatMap((x) => Object.keys(x))); // Determine the columns that could potentially be used for timestamp const remainingColumnsForTimestamp = difference(columnNames, [ @@ -84,4 +82,3 @@ export async function parsePreferenceTimestampsFromCsv( } return currentState; } -/* eslint-enable no-param-reassign */ diff --git a/src/lib/preference-management/tests/checkIfPendingPreferenceUpdatesAreNoOp.test.ts b/src/lib/preference-management/tests/checkIfPendingPreferenceUpdatesAreNoOp.test.ts index 81dfc6c5..7d6bec73 100644 --- a/src/lib/preference-management/tests/checkIfPendingPreferenceUpdatesAreNoOp.test.ts +++ b/src/lib/preference-management/tests/checkIfPendingPreferenceUpdatesAreNoOp.test.ts @@ -1,9 +1,7 @@ -/* eslint-disable max-lines */ -import { expect, describe, it } from 'vitest'; - -import { checkIfPendingPreferenceUpdatesAreNoOp } from '../index'; import { PreferenceTopicType } from '@transcend-io/privacy-types'; +import { describe, expect, it } from 'vitest'; import { PreferenceTopic } from '../../graphql'; +import { checkIfPendingPreferenceUpdatesAreNoOp } from '../index'; const DEFAULT_VALUES = { userId: 'test@transcend.io', @@ -486,4 +484,3 @@ describe('checkIfPendingPreferenceUpdatesAreNoOp', () => { ).to.equal(false); }); }); -/* eslint-enable max-lines */ diff --git a/src/lib/preference-management/tests/checkIfPendingPreferenceUpdatesCauseConflict.test.ts b/src/lib/preference-management/tests/checkIfPendingPreferenceUpdatesCauseConflict.test.ts index 78dfb716..f2735fbf 100644 --- a/src/lib/preference-management/tests/checkIfPendingPreferenceUpdatesCauseConflict.test.ts +++ b/src/lib/preference-management/tests/checkIfPendingPreferenceUpdatesCauseConflict.test.ts @@ -1,9 +1,7 @@ -/* eslint-disable max-lines */ -import { expect, describe, it } from 'vitest'; - -import { checkIfPendingPreferenceUpdatesCauseConflict } from '../index'; import { PreferenceTopicType } from '@transcend-io/privacy-types'; +import { describe, expect, it } from 'vitest'; import { PreferenceTopic } from '../../graphql'; +import { checkIfPendingPreferenceUpdatesCauseConflict } from '../index'; const DEFAULT_VALUES = { userId: 'test@transcend.io', @@ -512,4 +510,3 @@ describe('checkIfPendingPreferenceUpdatesCauseConflict', () => { ).to.equal(true); }); }); -/* eslint-enable max-lines */ diff --git a/src/lib/preference-management/tests/getPreferenceUpdatesFromRow.test.ts b/src/lib/preference-management/tests/getPreferenceUpdatesFromRow.test.ts index 53e93a46..1c4a3c90 100644 --- a/src/lib/preference-management/tests/getPreferenceUpdatesFromRow.test.ts +++ b/src/lib/preference-management/tests/getPreferenceUpdatesFromRow.test.ts @@ -1,8 +1,6 @@ -/* eslint-disable max-lines */ -import { expect, describe, it } from 'vitest'; - -import { getPreferenceUpdatesFromRow } from '../index'; import { PreferenceTopicType } from '@transcend-io/privacy-types'; +import { describe, expect, it } from 'vitest'; +import { getPreferenceUpdatesFromRow } from '../index'; describe('getPreferenceUpdatesFromRow', () => { it('should parse boolean updates', () => { @@ -527,8 +525,8 @@ describe('getPreferenceUpdatesFromRow', () => { }, }); expect.fail('Should have thrown'); - } catch (err) { - expect(err.message).to.include('No mapping provided'); + } catch (error) { + expect(error.message).to.include('No mapping provided'); } }); @@ -591,8 +589,8 @@ describe('getPreferenceUpdatesFromRow', () => { }, }); expect.fail('Should have thrown'); - } catch (err) { - expect(err.message).to.equal( + } catch (error) { + expect(error.message).to.equal( 'Invalid purpose slug: InvalidPurpose, expected: Marketing, Advertising', ); } @@ -653,8 +651,8 @@ describe('getPreferenceUpdatesFromRow', () => { }, }); expect.fail('Should have thrown'); - } catch (err) { - expect(err.message).to.equal( + } catch (error) { + expect(error.message).to.equal( 'Invalid value for select preference: SingleSelectPreference, expected string or null, got: true', ); } @@ -715,11 +713,10 @@ describe('getPreferenceUpdatesFromRow', () => { }, }); expect.fail('Should have thrown'); - } catch (err) { - expect(err.message).to.equal( + } catch (error) { + expect(error.message).to.equal( 'Invalid value for multi select preference: MultiSelectPreference, expected one of: Value1, Value2, got: true', ); } }); }); -/* eslint-enable max-lines */ diff --git a/src/lib/preference-management/uploadPreferenceManagementPreferencesInteractive.ts b/src/lib/preference-management/uploadPreferenceManagementPreferencesInteractive.ts index 2ae62080..0f592e5e 100644 --- a/src/lib/preference-management/uploadPreferenceManagementPreferencesInteractive.ts +++ b/src/lib/preference-management/uploadPreferenceManagementPreferencesInteractive.ts @@ -1,25 +1,25 @@ +import { PersistedState } from '@transcend-io/persisted-state'; +import { PreferenceUpdateItem } from '@transcend-io/privacy-types'; +import { apply } from '@transcend-io/type-utils'; +import cliProgress from 'cli-progress'; +import colors from 'colors'; +import { chunk } from 'lodash-es'; +import { DEFAULT_TRANSCEND_CONSENT_API } from '../../constants'; +import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; import { buildTranscendGraphQLClient, createSombraGotInstance, - fetchAllPurposes, fetchAllPreferenceTopics, + fetchAllPurposes, PreferenceTopic, Purpose, } from '../graphql'; -import colors from 'colors'; -import { map } from '../bluebird-replace'; -import { chunk } from 'lodash-es'; -import { DEFAULT_TRANSCEND_CONSENT_API } from '../../constants'; -import { logger } from '../../logger'; -import cliProgress from 'cli-progress'; import { parseAttributesFromString } from '../requests'; -import { PersistedState } from '@transcend-io/persisted-state'; -import { parsePreferenceManagementCsvWithCache } from './parsePreferenceManagementCsv'; import { PreferenceState } from './codecs'; -import { PreferenceUpdateItem } from '@transcend-io/privacy-types'; -import { apply } from '@transcend-io/type-utils'; -import { NONE_PREFERENCE_MAP } from './parsePreferenceTimestampsFromCsv'; import { getPreferenceUpdatesFromRow } from './getPreferenceUpdatesFromRow'; +import { parsePreferenceManagementCsvWithCache } from './parsePreferenceManagementCsv'; +import { NONE_PREFERENCE_MAP } from './parsePreferenceTimestampsFromCsv'; /** * Upload a set of consent preferences @@ -159,12 +159,12 @@ export async function uploadPreferenceManagementPreferencesInteractive({ ); // Update either safe updates only or safe + conflict - Object.entries({ + for (const [userId, update] of Object.entries({ ...metadata.pendingSafeUpdates, ...(skipConflictUpdates ? {} : apply(metadata.pendingConflictUpdates, ({ row }) => row)), - }).forEach(([userId, update]) => { + })) { // Determine timestamp const timestamp = metadata.timestampColum === NONE_PREFERENCE_MAP @@ -192,7 +192,7 @@ export async function uploadPreferenceManagementPreferencesInteractive({ }, })), }; - }); + } await preferenceState.setValue(pendingUpdates, 'pendingUpdates'); await preferenceState.setValue({}, 'failingUpdates'); @@ -217,7 +217,7 @@ export async function uploadPreferenceManagementPreferencesInteractive({ ); // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( @@ -244,13 +244,13 @@ export async function uploadPreferenceManagementPreferencesInteractive({ }, }) .json(); - } catch (err) { + } catch (error) { try { - const parsed = JSON.parse(err?.response?.body || '{}'); + const parsed = JSON.parse(error?.response?.body || '{}'); if (parsed.error) { logger.error(colors.red(`Error: ${parsed.error}`)); } - } catch (e) { + } catch { // continue } logger.error( @@ -258,18 +258,18 @@ export async function uploadPreferenceManagementPreferencesInteractive({ `Failed to upload ${ currentChunk.length } user preferences to partition ${partition}: ${ - err?.response?.body || err?.message + error?.response?.body || error?.message }`, ), ); const failingUpdates = preferenceState.getValue('failingUpdates'); - currentChunk.forEach(([userId, update]) => { + for (const [userId, update] of currentChunk) { failingUpdates[userId] = { uploadedAt: new Date().toISOString(), update, - error: err?.response?.body || err?.message || 'Unknown error', + error: error?.response?.body || error?.message || 'Unknown error', }; - }); + } await preferenceState.setValue(failingUpdates, 'failingUpdates'); } @@ -282,7 +282,7 @@ export async function uploadPreferenceManagementPreferencesInteractive({ ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( colors.green( diff --git a/src/lib/readTranscendYaml.ts b/src/lib/readTranscendYaml.ts index 4a3428e4..ea8e645e 100644 --- a/src/lib/readTranscendYaml.ts +++ b/src/lib/readTranscendYaml.ts @@ -1,6 +1,6 @@ +import { readFileSync, writeFileSync } from 'node:fs'; import { decodeCodec, ObjByString } from '@transcend-io/type-utils'; import yaml from 'js-yaml'; -import { readFileSync, writeFileSync } from 'fs'; import { TranscendInput } from '../codecs'; export const VARIABLE_PARAMETERS_REGEXP = /<>/; @@ -22,11 +22,11 @@ export function replaceVariablesInYaml( ): string { let contents = input; // Replace variables - Object.entries(variables).forEach(([name, value]) => { + for (const [name, value] of Object.entries(variables)) { contents = contents .split(`<<${VARIABLE_PARAMETERS_NAME}.${name}>>`) .join(value); - }); + } // Throw error if unfilled variables if (VARIABLE_PARAMETERS_REGEXP.test(contents)) { diff --git a/src/lib/requests/approvePrivacyRequests.ts b/src/lib/requests/approvePrivacyRequests.ts index 58a62ea8..dd331f2e 100644 --- a/src/lib/requests/approvePrivacyRequests.ts +++ b/src/lib/requests/approvePrivacyRequests.ts @@ -1,20 +1,20 @@ -import { map } from '../bluebird-replace'; -import colors from 'colors'; -import { logger } from '../../logger'; import { RequestAction, RequestOrigin, RequestStatus, } from '@transcend-io/privacy-types'; +import cliProgress from 'cli-progress'; +import colors from 'colors'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; +import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; import { - UPDATE_PRIVACY_REQUEST, + APPROVE_PRIVACY_REQUEST, + buildTranscendGraphQLClient, fetchAllRequests, makeGraphQLRequest, - buildTranscendGraphQLClient, - APPROVE_PRIVACY_REQUEST, + UPDATE_PRIVACY_REQUEST, } from '../graphql'; -import cliProgress from 'cli-progress'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; /** * Approve a set of privacy requests @@ -53,7 +53,7 @@ export async function approvePrivacyRequests({ const client = buildTranscendGraphQLClient(transcendUrl, auth); // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( {}, @@ -97,8 +97,8 @@ export async function approvePrivacyRequests({ await makeGraphQLRequest(client, APPROVE_PRIVACY_REQUEST, { input: { requestId: requestToApprove.id }, }); - } catch (err) { - if (err.message.includes('Request must be in an approving state,')) { + } catch (error) { + if (error.message.includes('Request must be in an approving state,')) { skipped += 1; } } @@ -110,7 +110,7 @@ export async function approvePrivacyRequests({ ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; if (skipped > 0) { logger.info(colors.yellow(`${skipped} requests were skipped.`)); diff --git a/src/lib/requests/bulkRestartRequests.ts b/src/lib/requests/bulkRestartRequests.ts index 9422b390..07a04e91 100644 --- a/src/lib/requests/bulkRestartRequests.ts +++ b/src/lib/requests/bulkRestartRequests.ts @@ -1,19 +1,19 @@ +import { join } from 'node:path'; import { PersistedState } from '@transcend-io/persisted-state'; import { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; -import { map } from '../bluebird-replace'; import cliProgress from 'cli-progress'; import colors from 'colors'; import * as t from 'io-ts'; import { difference } from 'lodash-es'; -import { join } from 'path'; import { DEFAULT_TRANSCEND_API } from '../../constants'; +import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; import { buildTranscendGraphQLClient, createSombraGotInstance, fetchAllRequestIdentifiers, fetchAllRequests, } from '../graphql'; -import { logger } from '../../logger'; import { SuccessfulRequest } from './constants'; import { extractClientError } from './extractClientError'; import { restartPrivacyRequest } from './restartPrivacyRequest'; @@ -92,7 +92,7 @@ export async function bulkRestartRequests({ concurrency?: number; }): Promise { // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( {}, @@ -198,13 +198,13 @@ export async function bulkRestartRequests({ attemptedAt: new Date().toISOString(), }); await state.setValue(restartedRequests, 'restartedRequests'); - } catch (err) { - const msg = `${err.message} - ${JSON.stringify( - err.response?.body, + } catch (error) { + const message = `${error.message} - ${JSON.stringify( + error.response?.body, null, 2, )}`; - const clientError = extractClientError(msg); + const clientError = extractClientError(message); const failingRequests = state.getValue('failingRequests'); failingRequests.push({ @@ -213,7 +213,7 @@ export async function bulkRestartRequests({ rowIndex: ind, coreIdentifier: request.coreIdentifier, attemptedAt: new Date().toISOString(), - error: clientError || msg, + error: clientError || message, }); await state.setValue(failingRequests, 'failingRequests'); } @@ -224,7 +224,7 @@ export async function bulkRestartRequests({ ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; // Log completion time diff --git a/src/lib/requests/bulkRetryEnrichers.ts b/src/lib/requests/bulkRetryEnrichers.ts index 2485e075..d854fb35 100644 --- a/src/lib/requests/bulkRetryEnrichers.ts +++ b/src/lib/requests/bulkRetryEnrichers.ts @@ -3,18 +3,18 @@ import { RequestEnricherStatus, RequestStatus, } from '@transcend-io/privacy-types'; -import { map } from '../bluebird-replace'; import cliProgress from 'cli-progress'; import colors from 'colors'; import { difference } from 'lodash-es'; import { DEFAULT_TRANSCEND_API } from '../../constants'; +import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; import { buildTranscendGraphQLClient, fetchAllRequestEnrichers, fetchAllRequests, retryRequestEnricher, } from '../graphql'; -import { logger } from '../../logger'; /** * Restart a bunch of request enrichers @@ -52,7 +52,7 @@ export async function bulkRetryEnrichers({ concurrency?: number; }): Promise { // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( {}, @@ -120,7 +120,7 @@ export async function bulkRetryEnrichers({ ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; // Log completion time diff --git a/src/lib/requests/cancelPrivacyRequests.ts b/src/lib/requests/cancelPrivacyRequests.ts index 9bea901f..815ff5d5 100644 --- a/src/lib/requests/cancelPrivacyRequests.ts +++ b/src/lib/requests/cancelPrivacyRequests.ts @@ -1,18 +1,18 @@ -import { map } from '../bluebird-replace'; +import { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; +import cliProgress from 'cli-progress'; import colors from 'colors'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; import { logger } from '../../logger'; -import { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; +import { map } from '../bluebird-replace'; import { - UPDATE_PRIVACY_REQUEST, - fetchAllRequests, - makeGraphQLRequest, buildTranscendGraphQLClient, CANCEL_PRIVACY_REQUEST, + fetchAllRequests, fetchAllTemplates, + makeGraphQLRequest, Template, + UPDATE_PRIVACY_REQUEST, } from '../graphql'; -import cliProgress from 'cli-progress'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; /** * Cancel a set of privacy requests @@ -66,7 +66,7 @@ export async function cancelPrivacyRequests({ const client = buildTranscendGraphQLClient(transcendUrl, auth); // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( {}, @@ -150,7 +150,7 @@ export async function cancelPrivacyRequests({ ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( diff --git a/src/lib/requests/constants.ts b/src/lib/requests/constants.ts index 5720dbaf..d917b352 100644 --- a/src/lib/requests/constants.ts +++ b/src/lib/requests/constants.ts @@ -1,11 +1,11 @@ -import { applyEnum, valuesOf } from '@transcend-io/type-utils'; import { LanguageKey } from '@transcend-io/internationalization'; import { CompletedRequestStatus, - RequestAction, IsoCountryCode, IsoCountrySubdivisionCode, + RequestAction, } from '@transcend-io/privacy-types'; +import { applyEnum, valuesOf } from '@transcend-io/type-utils'; import * as t from 'io-ts'; export const NONE = '[NONE]' as const; @@ -42,7 +42,7 @@ export enum ColumnName { } /** These parameters are required in the Transcend DSR API */ -export const IS_REQUIRED: { [k in ColumnName]: boolean } = { +export const IS_REQUIRED: Record = { [ColumnName.Email]: false, [ColumnName.CoreIdentifier]: true, [ColumnName.RequestType]: true, @@ -56,7 +56,7 @@ export const IS_REQUIRED: { [k in ColumnName]: boolean } = { }; /** These parameters can be specified for the entire CSV set if needed */ -export const CAN_APPLY_IN_BULK: { [k in ColumnName]?: boolean } = { +export const CAN_APPLY_IN_BULK: Partial> = { [ColumnName.RequestType]: true, [ColumnName.SubjectType]: true, }; diff --git a/src/lib/requests/downloadPrivacyRequestFiles.ts b/src/lib/requests/downloadPrivacyRequestFiles.ts index e133730f..83fc4ee1 100644 --- a/src/lib/requests/downloadPrivacyRequestFiles.ts +++ b/src/lib/requests/downloadPrivacyRequestFiles.ts @@ -1,18 +1,18 @@ -import { map } from '../bluebird-replace'; -import { existsSync, mkdirSync, writeFileSync } from 'fs'; -import { dirname, join } from 'path'; +import { existsSync, mkdirSync, writeFileSync } from 'node:fs'; +import { dirname, join } from 'node:path'; +import { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; +import cliProgress from 'cli-progress'; import colors from 'colors'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; import { logger } from '../../logger'; -import { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; +import { map } from '../bluebird-replace'; import { - fetchAllRequests, + APPROVE_PRIVACY_REQUEST, buildTranscendGraphQLClient, createSombraGotInstance, + fetchAllRequests, makeGraphQLRequest, - APPROVE_PRIVACY_REQUEST, } from '../graphql'; -import cliProgress from 'cli-progress'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; import { getFileMetadataForPrivacyRequests } from './getFileMetadataForPrivacyRequests'; import { streamPrivacyRequestFiles } from './streamPrivacyRequestFiles'; @@ -85,7 +85,7 @@ export async function downloadPrivacyRequestFiles({ ); // Start timer for download process - const t0 = new Date().getTime(); + const t0 = Date.now(); const progressBar = new cliProgress.SingleBar( {}, cliProgress.Presets.shades_classic, @@ -138,7 +138,7 @@ export async function downloadPrivacyRequestFiles({ ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( diff --git a/src/lib/requests/extractClientError.ts b/src/lib/requests/extractClientError.ts index 8f7b85b3..41eb2e58 100644 --- a/src/lib/requests/extractClientError.ts +++ b/src/lib/requests/extractClientError.ts @@ -6,6 +6,6 @@ const CLIENT_ERROR = /{\\"message\\":\\"(.+?)\\",/; * @param err - Error message * @returns Client error or null */ -export function extractClientError(err: string): string | null { - return CLIENT_ERROR.test(err) ? CLIENT_ERROR.exec(err)![1] : null; +export function extractClientError(error: string): string | null { + return CLIENT_ERROR.test(error) ? CLIENT_ERROR.exec(error)![1] : null; } diff --git a/src/lib/requests/filterRows.ts b/src/lib/requests/filterRows.ts index f192888c..ac289466 100644 --- a/src/lib/requests/filterRows.ts +++ b/src/lib/requests/filterRows.ts @@ -1,6 +1,6 @@ -import inquirer from 'inquirer'; import { ObjByString } from '@transcend-io/type-utils'; import colors from 'colors'; +import inquirer from 'inquirer'; import { uniq } from 'lodash-es'; import { logger } from '../../logger'; import { NONE } from './constants'; @@ -15,7 +15,7 @@ import { getUniqueValuesForColumn } from './getUniqueValuesForColumn'; */ export async function filterRows(rows: ObjByString[]): Promise { // Determine set of column names - const columnNames = uniq(rows.map((x) => Object.keys(x)).flat()); + const columnNames = uniq(rows.flatMap((x) => Object.keys(x))); // update these variables recursively let filteredRows = rows; @@ -31,7 +31,7 @@ export async function filterRows(rows: ObjByString[]): Promise { }>([ { name: 'filterColumnName', - // eslint-disable-next-line max-len + message: `If you need to filter the list of requests to import, choose the column to filter on. Currently ${filteredRows.length} rows.`, type: 'list', default: columnNames, diff --git a/src/lib/requests/fuzzyMatchColumns.ts b/src/lib/requests/fuzzyMatchColumns.ts index 31735676..4673f934 100644 --- a/src/lib/requests/fuzzyMatchColumns.ts +++ b/src/lib/requests/fuzzyMatchColumns.ts @@ -1,7 +1,6 @@ -import inquirer from 'inquirer'; -import { NONE, BULK_APPLY } from './constants'; - import fuzzysearch from 'fuzzysearch'; +import inquirer from 'inquirer'; +import { BULK_APPLY, NONE } from './constants'; /** * Check if word1 and word2 are a fuzzy match of each other. diff --git a/src/lib/requests/getFileMetadataForPrivacyRequests.ts b/src/lib/requests/getFileMetadataForPrivacyRequests.ts index 4c2abf3e..0c856642 100644 --- a/src/lib/requests/getFileMetadataForPrivacyRequests.ts +++ b/src/lib/requests/getFileMetadataForPrivacyRequests.ts @@ -1,13 +1,12 @@ -import { map } from '../bluebird-replace'; -import colors from 'colors'; +import { TableEncryptionType } from '@transcend-io/privacy-types'; +import { decodeCodec, valuesOf } from '@transcend-io/type-utils'; import cliProgress from 'cli-progress'; - -import { PrivacyRequest } from '../graphql'; -import * as t from 'io-ts'; +import colors from 'colors'; import type { Got } from 'got'; -import { decodeCodec, valuesOf } from '@transcend-io/type-utils'; +import * as t from 'io-ts'; import { logger } from '../../logger'; -import { TableEncryptionType } from '@transcend-io/privacy-types'; +import { map } from '../bluebird-replace'; +import { PrivacyRequest } from '../graphql'; export const IntlMessage = t.type({ /** The message key */ @@ -113,7 +112,7 @@ export async function getFileMetadataForPrivacyRequests( ); // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( {}, @@ -159,12 +158,11 @@ export async function getFileMetadataForPrivacyRequests( // Increase offset and break if no more pages offset += limit; shouldContinue = - // eslint-disable-next-line no-underscore-dangle !!response._links.next && response.nodes.length === limit; - } catch (err) { + } catch (error) { throw new Error( `Received an error from server: ${ - err?.response?.body || err?.message + error?.response?.body || error?.message }`, ); } @@ -178,7 +176,7 @@ export async function getFileMetadataForPrivacyRequests( ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( diff --git a/src/lib/requests/getUniqueValuesForColumn.ts b/src/lib/requests/getUniqueValuesForColumn.ts index 731210ca..99527b67 100644 --- a/src/lib/requests/getUniqueValuesForColumn.ts +++ b/src/lib/requests/getUniqueValuesForColumn.ts @@ -12,5 +12,5 @@ export function getUniqueValuesForColumn( rows: ObjByString[], columnName: string, ): string[] { - return uniq(rows.map((row) => row[columnName] || '').flat()); + return uniq(rows.flatMap((row) => row[columnName] || '')); } diff --git a/src/lib/requests/mapColumnsToAttributes.ts b/src/lib/requests/mapColumnsToAttributes.ts index 15e65988..fa86032b 100644 --- a/src/lib/requests/mapColumnsToAttributes.ts +++ b/src/lib/requests/mapColumnsToAttributes.ts @@ -1,16 +1,14 @@ +import type { PersistedState } from '@transcend-io/persisted-state'; import type { GraphQLClient } from 'graphql-request'; import inquirer from 'inquirer'; import { AttributeKey } from '../graphql'; import { CachedFileState } from './constants'; import { fuzzyMatchColumns } from './fuzzyMatchColumns'; -import type { PersistedState } from '@transcend-io/persisted-state'; /** * Mapping from attribute name to request input parameter */ -export type AttributeNameMap = { - [k in string]: string; -}; +export type AttributeNameMap = Record; /** * Create a mapping from the attributes names that can be included @@ -39,9 +37,7 @@ export async function mapColumnsToAttributes( columnQuestions.length === 0 ? {} : // prompt questions to map columns - await inquirer.prompt<{ - [k in string]: string; - }>( + await inquirer.prompt>( columnQuestions.map(({ name }) => { const matches = fuzzyMatchColumns(columnNames, name, false); return { diff --git a/src/lib/requests/mapColumnsToIdentifiers.ts b/src/lib/requests/mapColumnsToIdentifiers.ts index 6bec8709..d88deaea 100644 --- a/src/lib/requests/mapColumnsToIdentifiers.ts +++ b/src/lib/requests/mapColumnsToIdentifiers.ts @@ -1,16 +1,14 @@ +import type { PersistedState } from '@transcend-io/persisted-state'; import type { GraphQLClient } from 'graphql-request'; import inquirer from 'inquirer'; -import { INITIALIZER, makeGraphQLRequest, Initializer } from '../graphql'; +import { INITIALIZER, Initializer, makeGraphQLRequest } from '../graphql'; import { CachedFileState, IDENTIFIER_BLOCK_LIST } from './constants'; import { fuzzyMatchColumns } from './fuzzyMatchColumns'; -import type { PersistedState } from '@transcend-io/persisted-state'; /** * Mapping from identifier name to request input parameter */ -export type IdentifierNameMap = { - [k in string]: string; -}; +export type IdentifierNameMap = Record; /** * Create a mapping from the identifier names that can be included @@ -45,9 +43,7 @@ export async function mapColumnsToIdentifiers( columnQuestions.length === 0 ? {} : // prompt questions to map columns - await inquirer.prompt<{ - [k in string]: string; - }>( + await inquirer.prompt>( columnQuestions.map(({ name }) => { const matches = fuzzyMatchColumns(columnNames, name, false); return { diff --git a/src/lib/requests/mapCsvColumnsToApi.ts b/src/lib/requests/mapCsvColumnsToApi.ts index e920ec66..11547c04 100644 --- a/src/lib/requests/mapCsvColumnsToApi.ts +++ b/src/lib/requests/mapCsvColumnsToApi.ts @@ -1,21 +1,19 @@ -import { getValues, getEntries } from '@transcend-io/type-utils'; import type { PersistedState } from '@transcend-io/persisted-state'; +import { getEntries, getValues } from '@transcend-io/type-utils'; import inquirer from 'inquirer'; import { startCase } from 'lodash-es'; import { - ColumnName, CachedFileState, - IS_REQUIRED, CAN_APPLY_IN_BULK, + ColumnName, + IS_REQUIRED, } from './constants'; import { fuzzyMatchColumns } from './fuzzyMatchColumns'; /** * Mapping from column name to request input parameter */ -export type ColumnNameMap = { - [k in ColumnName]?: string; -}; +export type ColumnNameMap = Partial>; /** * Determine the mapping between columns in CSV @@ -38,9 +36,7 @@ export async function mapCsvColumnsToApi( columnQuestions.length === 0 ? {} : // prompt questions to map columns - await inquirer.prompt<{ - [k in ColumnName]?: string; - }>( + await inquirer.prompt>>( columnQuestions.map((name) => { const field = startCase(name.replace('ColumnName', '')); const matches = fuzzyMatchColumns( diff --git a/src/lib/requests/mapCsvRowsToRequestInputs.ts b/src/lib/requests/mapCsvRowsToRequestInputs.ts index 9659bd94..da8ebefa 100644 --- a/src/lib/requests/mapCsvRowsToRequestInputs.ts +++ b/src/lib/requests/mapCsvRowsToRequestInputs.ts @@ -1,31 +1,29 @@ import { LanguageKey } from '@transcend-io/internationalization'; -import { DateFromISOString } from 'io-ts-types'; - -import * as t from 'io-ts'; import type { PersistedState } from '@transcend-io/persisted-state'; import { - NORMALIZE_PHONE_NUMBER, CompletedRequestStatus, - RequestAction, IdentifierType, IsoCountryCode, IsoCountrySubdivisionCode, + NORMALIZE_PHONE_NUMBER, + RequestAction, } from '@transcend-io/privacy-types'; import { ObjByString, valuesOf } from '@transcend-io/type-utils'; - +import * as t from 'io-ts'; +import { DateFromISOString } from 'io-ts-types'; +import { AttributeKey } from '../graphql'; import { - CachedFileState, BLANK, BULK_APPLY, + CachedFileState, ColumnName, NONE, } from './constants'; -import { AttributeKey } from '../graphql'; -import { ColumnNameMap } from './mapCsvColumnsToApi'; -import { splitCsvToList } from './splitCsvToList'; -import { ParsedAttributeInput } from './parseAttributesFromString'; import { AttributeNameMap } from './mapColumnsToAttributes'; import { IdentifierNameMap } from './mapColumnsToIdentifiers'; +import { ColumnNameMap } from './mapCsvColumnsToApi'; +import { ParsedAttributeInput } from './parseAttributesFromString'; +import { splitCsvToList } from './splitCsvToList'; /** * Shape of additional identifiers @@ -109,16 +107,16 @@ export function normalizeIdentifierValue( if (identifierType === IdentifierType.Phone) { const normalized = identifierValue .replace(NORMALIZE_PHONE_NUMBER, '') - .replace(/[()]/g, '') - .replace(/[–]/g, '') - .replace(/[:]/g, '') - .replace(/[‭‬]/g, '') - .replace(/[A-Za-z]/g, ''); - return !normalized - ? '' - : normalized.startsWith('+') - ? normalized - : `+${defaultPhoneCountryCode}${normalized}`; + .replaceAll(/[()]/g, '') + .replaceAll(/[–]/g, '') + .replaceAll(/[:]/g, '') + .replaceAll(/[‭‬]/g, '') + .replaceAll(/[A-Za-z]/g, ''); + return normalized + ? normalized.startsWith('+') + ? normalized + : `+${defaultPhoneCountryCode}${normalized}` + : ''; } return identifierValue; } @@ -162,61 +160,62 @@ export function mapCsvRowsToRequestInputs( (input): [Record, PrivacyRequestInput] => { // The extra identifiers to upload for this request const attestedExtraIdentifiers: AttestedExtraIdentifiers = {}; - Object.entries(identifierNameMap) + for (const [identifierName, columnName] of Object.entries( + identifierNameMap, + ) // filter out skipped identifiers - .filter(([, columnName]) => columnName !== NONE) - .forEach(([identifierName, columnName]) => { - // Determine the identifier type being specified - const identifierType = Object.values(IdentifierType).includes( - identifierName as any, // eslint-disable-line @typescript-eslint/no-explicit-any - ) - ? (identifierName as IdentifierType) - : IdentifierType.Custom; + .filter(([, columnName]) => columnName !== NONE)) { + // Determine the identifier type being specified + const identifierType = Object.values(IdentifierType).includes( + identifierName as any, // eslint-disable-line @typescript-eslint/no-explicit-any + ) + ? (identifierName as IdentifierType) + : IdentifierType.Custom; - // Only add the identifier if the value exists - const identifierValue = input[columnName]; - if (identifierValue) { - const normalized = normalizeIdentifierValue( - identifierValue, - identifierType, - defaultPhoneCountryCode, - ); - if (normalized) { - // Initialize - if (!attestedExtraIdentifiers[identifierType]) { - attestedExtraIdentifiers[identifierType] = []; - } - - // Add the identifier - attestedExtraIdentifiers[identifierType]!.push({ - value: normalized, - name: identifierName, - }); + // Only add the identifier if the value exists + const identifierValue = input[columnName]; + if (identifierValue) { + const normalized = normalizeIdentifierValue( + identifierValue, + identifierType, + defaultPhoneCountryCode, + ); + if (normalized) { + // Initialize + if (!attestedExtraIdentifiers[identifierType]) { + attestedExtraIdentifiers[identifierType] = []; } + + // Add the identifier + attestedExtraIdentifiers[identifierType].push({ + value: normalized, + name: identifierName, + }); } - }); + } + } // The extra attributes to upload for this request const attributes: ParsedAttributeInput[] = []; - Object.entries(attributeNameMap) + for (const [attributeName, columnName] of Object.entries(attributeNameMap) // filter out skipped attributes - .filter(([, columnName]) => columnName !== NONE) - .forEach(([attributeName, columnName]) => { - // Only add the identifier if the value exists - const attributeValueString = input[columnName]; - if (attributeValueString) { - // Add the attribute - const isMulti = - requestAttributeKeys.find((attr) => attr.name === attributeName) - ?.type === 'MULTI_SELECT'; - attributes.push({ - values: isMulti - ? splitCsvToList(attributeValueString) - : attributeValueString, - key: attributeName, - }); - } - }); + .filter(([, columnName]) => columnName !== NONE)) { + // Only add the identifier if the value exists + const attributeValueString = input[columnName]; + if (attributeValueString) { + // Add the attribute + const isMulti = + requestAttributeKeys.find( + (attribute) => attribute.name === attributeName, + )?.type === 'MULTI_SELECT'; + attributes.push({ + values: isMulti + ? splitCsvToList(attributeValueString) + : attributeValueString, + key: attributeName, + }); + } + } const requestTypeColumn = getMappedName(ColumnName.RequestType); const dataSubjectTypeColumn = getMappedName(ColumnName.SubjectType); diff --git a/src/lib/requests/mapEnumValues.ts b/src/lib/requests/mapEnumValues.ts index 2c85aaa9..d53b4388 100644 --- a/src/lib/requests/mapEnumValues.ts +++ b/src/lib/requests/mapEnumValues.ts @@ -1,6 +1,6 @@ +import { apply, ObjByString } from '@transcend-io/type-utils'; import inquirer from 'inquirer'; import autoCompletePrompt from 'inquirer-autocomplete-prompt'; -import { apply, ObjByString } from '@transcend-io/type-utils'; import { fuzzySearch } from './fuzzyMatchColumns'; /** @@ -14,8 +14,8 @@ import { fuzzySearch } from './fuzzyMatchColumns'; export async function mapEnumValues( csvInputs: string[], expectedOutputs: TValue[], - cache: { [k in string]: TValue }, -): Promise<{ [k in string]: TValue }> { + cache: Record, +): Promise> { inquirer.registerPrompt('autocomplete', autoCompletePrompt); const inputs = csvInputs @@ -24,24 +24,24 @@ export async function mapEnumValues( if (inputs.length === 0) { return cache; } - const result = await inquirer.prompt<{ [k in string]: TValue }>( + const result = await inquirer.prompt>( inputs.map((value) => ({ name: value, message: `Map value of: ${value}`, type: 'autocomplete', default: expectedOutputs.find((x) => fuzzySearch(value, x)), source: (answersSoFar: ObjByString, input: string) => - !input - ? expectedOutputs - : expectedOutputs.filter( + input + ? expectedOutputs.filter( (x) => typeof x === 'string' && fuzzySearch(input, x), - ), + ) + : expectedOutputs, })), ); return { ...cache, ...apply(result, (r) => - typeof r === 'string' ? (r as TValue) : (Object.values(r)[0] as TValue), + typeof r === 'string' ? r : (Object.values(r)[0] as TValue), ), }; } diff --git a/src/lib/requests/mapRequestEnumValues.ts b/src/lib/requests/mapRequestEnumValues.ts index 15c4a07c..baf2ee61 100644 --- a/src/lib/requests/mapRequestEnumValues.ts +++ b/src/lib/requests/mapRequestEnumValues.ts @@ -1,20 +1,20 @@ -import { GraphQLClient } from 'graphql-request'; -import colors from 'colors'; +import { LanguageKey } from '@transcend-io/internationalization'; import type { PersistedState } from '@transcend-io/persisted-state'; import { CompletedRequestStatus, - RequestAction, IsoCountryCode, IsoCountrySubdivisionCode, + RequestAction, } from '@transcend-io/privacy-types'; -import { LanguageKey } from '@transcend-io/internationalization'; import { ObjByString } from '@transcend-io/type-utils'; +import colors from 'colors'; +import { GraphQLClient } from 'graphql-request'; import { logger } from '../../logger'; -import { makeGraphQLRequest, DataSubject, DATA_SUBJECTS } from '../graphql'; -import { CachedFileState, NONE, ColumnName } from './constants'; -import { mapEnumValues } from './mapEnumValues'; -import { ColumnNameMap } from './mapCsvColumnsToApi'; +import { DATA_SUBJECTS, DataSubject, makeGraphQLRequest } from '../graphql'; +import { CachedFileState, ColumnName, NONE } from './constants'; import { getUniqueValuesForColumn } from './getUniqueValuesForColumn'; +import { ColumnNameMap } from './mapCsvColumnsToApi'; +import { mapEnumValues } from './mapEnumValues'; /** * Map the values in a CSV to the enum values in Transcend @@ -50,7 +50,7 @@ export async function mapRequestEnumValues( logger.info( colors.magenta('Determining mapping of columns for request action'), ); - const requestTypeToRequestAction: { [k in string]: RequestAction } = + const requestTypeToRequestAction: Record = await mapEnumValues( getUniqueValuesForColumn(requests, getMappedName(ColumnName.RequestType)), Object.values(RequestAction), @@ -63,17 +63,16 @@ export async function mapRequestEnumValues( // Map data subject type logger.info(colors.magenta('Determining mapping of columns for subject')); - const subjectTypeToSubjectName: { [k in string]: string } = - await mapEnumValues( - getUniqueValuesForColumn(requests, getMappedName(ColumnName.SubjectType)), - internalSubjects.map(({ type }) => type), - state.getValue('subjectTypeToSubjectName'), - ); + const subjectTypeToSubjectName: Record = await mapEnumValues( + getUniqueValuesForColumn(requests, getMappedName(ColumnName.SubjectType)), + internalSubjects.map(({ type }) => type), + state.getValue('subjectTypeToSubjectName'), + ); await state.setValue(subjectTypeToSubjectName, 'subjectTypeToSubjectName'); // Map locale logger.info(colors.magenta('Determining mapping of columns for locale')); - const languageToLocale: { [k in string]: LanguageKey } = await mapEnumValues( + const languageToLocale: Record = await mapEnumValues( getUniqueValuesForColumn(requests, getMappedName(ColumnName.Locale)), Object.values(LanguageKey), state.getValue('languageToLocale'), @@ -88,9 +87,10 @@ export async function mapRequestEnumValues( colors.magenta('Determining mapping of columns for request status'), ); const requestStatusColumn = getMappedName(ColumnName.RequestStatus); - const statusToRequestStatus: { - [k in string]: CompletedRequestStatus | typeof NONE; - } = + const statusToRequestStatus: Record< + string, + CompletedRequestStatus | typeof NONE + > = requestStatusColumn === NONE ? {} : await mapEnumValues( @@ -103,9 +103,7 @@ export async function mapRequestEnumValues( // Map country logger.info(colors.magenta('Determining mapping of columns for country')); const countryColumn = getMappedName(ColumnName.Country); - const regionToCountry: { - [k in string]: IsoCountryCode | typeof NONE; - } = + const regionToCountry: Record = countryColumn === NONE ? {} : await mapEnumValues( @@ -120,9 +118,10 @@ export async function mapRequestEnumValues( colors.magenta('Determining mapping of columns for country sub division'), ); const countrySubDivisionColumn = getMappedName(ColumnName.CountrySubDivision); - const regionToCountrySubDivision: { - [k in string]: IsoCountrySubdivisionCode | typeof NONE; - } = + const regionToCountrySubDivision: Record< + string, + IsoCountrySubdivisionCode | typeof NONE + > = countrySubDivisionColumn === NONE ? {} : await mapEnumValues( diff --git a/src/lib/requests/markSilentPrivacyRequests.ts b/src/lib/requests/markSilentPrivacyRequests.ts index 88a437ce..eb6dc7e7 100644 --- a/src/lib/requests/markSilentPrivacyRequests.ts +++ b/src/lib/requests/markSilentPrivacyRequests.ts @@ -1,15 +1,15 @@ -import { map } from '../bluebird-replace'; +import { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; +import cliProgress from 'cli-progress'; import colors from 'colors'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; import { logger } from '../../logger'; -import { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; +import { map } from '../bluebird-replace'; import { - UPDATE_PRIVACY_REQUEST, + buildTranscendGraphQLClient, fetchAllRequests, makeGraphQLRequest, - buildTranscendGraphQLClient, + UPDATE_PRIVACY_REQUEST, } from '../graphql'; -import cliProgress from 'cli-progress'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; /** * Mark a set of privacy requests to be in silent mode @@ -57,7 +57,7 @@ export async function markSilentPrivacyRequests({ const client = buildTranscendGraphQLClient(transcendUrl, auth); // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( {}, @@ -98,7 +98,7 @@ export async function markSilentPrivacyRequests({ ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( diff --git a/src/lib/requests/notifyPrivacyRequestsAdditionalTime.ts b/src/lib/requests/notifyPrivacyRequestsAdditionalTime.ts index 59880ad4..9da01de9 100644 --- a/src/lib/requests/notifyPrivacyRequestsAdditionalTime.ts +++ b/src/lib/requests/notifyPrivacyRequestsAdditionalTime.ts @@ -1,16 +1,16 @@ -import { map } from '../bluebird-replace'; +import { RequestAction } from '@transcend-io/privacy-types'; +import cliProgress from 'cli-progress'; import colors from 'colors'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; import { logger } from '../../logger'; -import { RequestAction } from '@transcend-io/privacy-types'; +import { map } from '../bluebird-replace'; import { - NOTIFY_ADDITIONAL_TIME, - fetchAllRequests, - makeGraphQLRequest, buildTranscendGraphQLClient, + fetchAllRequests, fetchAllTemplates, + makeGraphQLRequest, + NOTIFY_ADDITIONAL_TIME, } from '../graphql'; -import cliProgress from 'cli-progress'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; /** * Mark a set of privacy requests to be in silent mode. @@ -59,7 +59,7 @@ export async function notifyPrivacyRequestsAdditionalTime({ const client = buildTranscendGraphQLClient(transcendUrl, auth); // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( {}, @@ -120,7 +120,7 @@ export async function notifyPrivacyRequestsAdditionalTime({ ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( diff --git a/src/lib/requests/pullPrivacyRequests.ts b/src/lib/requests/pullPrivacyRequests.ts index 33653b04..5ba70bbb 100644 --- a/src/lib/requests/pullPrivacyRequests.ts +++ b/src/lib/requests/pullPrivacyRequests.ts @@ -1,18 +1,17 @@ import { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; -import { map } from '../bluebird-replace'; import colors from 'colors'; import { groupBy } from 'lodash-es'; - import { DEFAULT_TRANSCEND_API } from '../../constants'; +import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; import { - PrivacyRequest, - RequestIdentifier, buildTranscendGraphQLClient, createSombraGotInstance, fetchAllRequestIdentifiers, fetchAllRequests, + PrivacyRequest, + RequestIdentifier, } from '../graphql'; -import { logger } from '../../logger'; export interface ExportedPrivacyRequest extends PrivacyRequest { /** Request identifiers */ @@ -61,9 +60,7 @@ export async function pullPrivacyRequests({ /** All request information with attached identifiers */ requestsWithRequestIdentifiers: ExportedPrivacyRequest[]; /** Requests that are formatted for CSV */ - requestsFormattedForCsv: { - [k in string]: string | null | number | boolean; - }[]; + requestsFormattedForCsv: Record[]; }> { // Find all requests made before createdAt that are in a removing data state const client = buildTranscendGraphQLClient(transcendUrl, auth); @@ -162,19 +159,18 @@ export async function pullPrivacyRequests({ 'Is Test Request': isTest, Language: locale, ...request, - ...Object.entries(groupBy(attributeValues, 'attributeKey.name')).reduce( - (acc, [name, values]) => - Object.assign(acc, { - [name]: values.map(({ name }) => name).join(','), - }), - {}, + ...Object.fromEntries( + Object.entries(groupBy(attributeValues, 'attributeKey.name')).map( + ([name, values]) => [name, values.map(({ name }) => name).join(',')], + ), ), - ...Object.entries(groupBy(requestIdentifiers, 'name')).reduce( - (acc, [name, values]) => - Object.assign(acc, { - [name]: values.map(({ value }) => value).join(','), - }), - {}, + ...Object.fromEntries( + Object.entries(groupBy(requestIdentifiers, 'name')).map( + ([name, values]) => [ + name, + values.map(({ value }) => value).join(','), + ], + ), ), }), ); diff --git a/src/lib/requests/readCsv.ts b/src/lib/requests/readCsv.ts index fe366e05..e949fe64 100644 --- a/src/lib/requests/readCsv.ts +++ b/src/lib/requests/readCsv.ts @@ -1,10 +1,9 @@ +import { readFileSync } from 'node:fs'; +import { decodeCodec } from '@transcend-io/type-utils'; import type { Options } from 'csv-parse'; import { parse } from 'csv-parse/sync'; -import { readFileSync } from 'fs'; import * as t from 'io-ts'; -import { decodeCodec } from '@transcend-io/type-utils'; - /** * Read in a CSV and validate its shape * @@ -27,9 +26,9 @@ export function readCsv( // remove any special characters from object keys const parsed = data.map((datum) => Object.entries(datum).reduce( - (acc, [key, value]) => - Object.assign(acc, { - [key.replace(/[^a-z_.+\-A-Z -~]/g, '')]: value, + (accumulator, [key, value]) => + Object.assign(accumulator, { + [key.replaceAll(/[^a-z_.+\-A-Z -~]/g, '')]: value, }), {} as T, ), diff --git a/src/lib/requests/removeUnverifiedRequestIdentifiers.ts b/src/lib/requests/removeUnverifiedRequestIdentifiers.ts index af4ebb36..0d4effc4 100644 --- a/src/lib/requests/removeUnverifiedRequestIdentifiers.ts +++ b/src/lib/requests/removeUnverifiedRequestIdentifiers.ts @@ -1,16 +1,16 @@ -import { map } from '../bluebird-replace'; +import { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; +import cliProgress from 'cli-progress'; import colors from 'colors'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; import { logger } from '../../logger'; -import { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; +import { map } from '../bluebird-replace'; import { - REMOVE_REQUEST_IDENTIFIERS, - fetchAllRequests, + buildTranscendGraphQLClient, fetchAllRequestIdentifierMetadata, + fetchAllRequests, makeGraphQLRequest, - buildTranscendGraphQLClient, + REMOVE_REQUEST_IDENTIFIERS, } from '../graphql'; -import cliProgress from 'cli-progress'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; /** * Remove a set of unverified request identifier @@ -40,7 +40,7 @@ export async function removeUnverifiedRequestIdentifiers({ const client = buildTranscendGraphQLClient(transcendUrl, auth); // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( {}, @@ -69,7 +69,7 @@ export async function removeUnverifiedRequestIdentifiers({ const clearOut = requestIdentifiers .filter( ({ isVerifiedAtLeastOnce, name }) => - isVerifiedAtLeastOnce === false && identifierNames.includes(name), + !isVerifiedAtLeastOnce && identifierNames.includes(name), ) .map(({ id }) => id); @@ -93,7 +93,7 @@ export async function removeUnverifiedRequestIdentifiers({ ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( diff --git a/src/lib/requests/restartPrivacyRequest.ts b/src/lib/requests/restartPrivacyRequest.ts index 81e58ca0..1e41f41c 100644 --- a/src/lib/requests/restartPrivacyRequest.ts +++ b/src/lib/requests/restartPrivacyRequest.ts @@ -1,8 +1,8 @@ -import * as t from 'io-ts'; -import { groupBy } from 'lodash-es'; -import { apply, decodeCodec } from '@transcend-io/type-utils'; import { IdentifierType } from '@transcend-io/privacy-types'; +import { apply, decodeCodec } from '@transcend-io/type-utils'; import type { Got } from 'got'; +import * as t from 'io-ts'; +import { groupBy } from 'lodash-es'; import { PrivacyRequest, RequestIdentifier } from '../graphql'; import { IDENTIFIER_BLOCK_LIST } from './constants'; import { PrivacyRequestResponse } from './submitPrivacyRequest'; diff --git a/src/lib/requests/retryRequestDataSilos.ts b/src/lib/requests/retryRequestDataSilos.ts index aade236f..bdcb9525 100644 --- a/src/lib/requests/retryRequestDataSilos.ts +++ b/src/lib/requests/retryRequestDataSilos.ts @@ -1,16 +1,16 @@ -import { map } from '../bluebird-replace'; +import { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; +import cliProgress from 'cli-progress'; import colors from 'colors'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; import { logger } from '../../logger'; -import { RequestAction, RequestStatus } from '@transcend-io/privacy-types'; +import { map } from '../bluebird-replace'; import { - RETRY_REQUEST_DATA_SILO, - fetchRequestDataSilo, + buildTranscendGraphQLClient, fetchAllRequests, + fetchRequestDataSilo, makeGraphQLRequest, - buildTranscendGraphQLClient, + RETRY_REQUEST_DATA_SILO, } from '../graphql'; -import cliProgress from 'cli-progress'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; /** * Retry a set of RequestDataSilos @@ -40,7 +40,7 @@ export async function retryRequestDataSilos({ const client = buildTranscendGraphQLClient(transcendUrl, auth); // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( {}, @@ -78,10 +78,10 @@ export async function retryRequestDataSilos({ }>(client, RETRY_REQUEST_DATA_SILO, { requestDataSiloId: requestDataSilo.id, }); - } catch (err) { + } catch (error) { // some requests may not have this data silo connected - if (!err.message.includes('Failed to find RequestDataSilo')) { - throw err; + if (!error.message.includes('Failed to find RequestDataSilo')) { + throw error; } skipped += 1; } @@ -93,7 +93,7 @@ export async function retryRequestDataSilos({ ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( diff --git a/src/lib/requests/skipPreflightJobs.ts b/src/lib/requests/skipPreflightJobs.ts index e303218a..893f6259 100644 --- a/src/lib/requests/skipPreflightJobs.ts +++ b/src/lib/requests/skipPreflightJobs.ts @@ -1,19 +1,19 @@ -import { mapSeries, map } from '../bluebird-replace'; +import { + RequestEnricherStatus, + RequestStatus, +} from '@transcend-io/privacy-types'; +import cliProgress from 'cli-progress'; import colors from 'colors'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; import { logger } from '../../logger'; +import { map, mapSeries } from '../bluebird-replace'; import { - makeGraphQLRequest, buildTranscendGraphQLClient, fetchAllRequestEnrichers, fetchAllRequests, + makeGraphQLRequest, SKIP_REQUEST_ENRICHER, } from '../graphql'; -import cliProgress from 'cli-progress'; -import { - RequestEnricherStatus, - RequestStatus, -} from '@transcend-io/privacy-types'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; /** * Given an enricher ID, mark all open request enrichers as skipped @@ -42,7 +42,7 @@ export async function skipPreflightJobs({ const client = buildTranscendGraphQLClient(transcendUrl, auth); // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // fetch all RequestDataSilos that are open const requests = await fetchAllRequests(client, { @@ -95,13 +95,13 @@ export async function skipPreflightJobs({ requestEnricherId: requestEnricher.id, }); totalSkipped += 1; - } catch (err) { + } catch (error) { if ( - !err.message.includes( + !error.message.includes( 'Client error: Cannot skip Request enricher because it has already completed', ) ) { - throw err; + throw error; } } }); @@ -113,7 +113,7 @@ export async function skipPreflightJobs({ ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( diff --git a/src/lib/requests/skipRequestDataSilos.ts b/src/lib/requests/skipRequestDataSilos.ts index 07544e6a..23000495 100644 --- a/src/lib/requests/skipRequestDataSilos.ts +++ b/src/lib/requests/skipRequestDataSilos.ts @@ -1,15 +1,15 @@ -import { map } from '../bluebird-replace'; +import { RequestStatus } from '@transcend-io/privacy-types'; +import cliProgress from 'cli-progress'; import colors from 'colors'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; import { - CHANGE_REQUEST_DATA_SILO_STATUS, - makeGraphQLRequest, buildTranscendGraphQLClient, + CHANGE_REQUEST_DATA_SILO_STATUS, fetchRequestDataSilos, + makeGraphQLRequest, } from '../graphql'; -import cliProgress from 'cli-progress'; -import { RequestStatus } from '@transcend-io/privacy-types'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; /** * Given a data silo ID, mark all open request data silos as skipped @@ -42,7 +42,7 @@ export async function skipRequestDataSilos({ const client = buildTranscendGraphQLClient(transcendUrl, auth); // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // fetch all RequestDataSilos that are open const requestDataSilos = await fetchRequestDataSilos(client, { @@ -76,9 +76,9 @@ export async function skipRequestDataSilos({ requestDataSiloId: requestDataSilo.id, status, }); - } catch (err) { - if (!err.message.includes('Client error: Request must be active:')) { - throw err; + } catch (error) { + if (!error.message.includes('Client error: Request must be active:')) { + throw error; } } @@ -89,7 +89,7 @@ export async function skipRequestDataSilos({ ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; logger.info( diff --git a/src/lib/requests/splitCsvToList.ts b/src/lib/requests/splitCsvToList.ts index adefd331..b937aa77 100644 --- a/src/lib/requests/splitCsvToList.ts +++ b/src/lib/requests/splitCsvToList.ts @@ -12,5 +12,5 @@ export function splitCsvToList(value: string): string[] { return value .split(',') .map((x) => x.trim()) - .filter((x) => x); + .filter(Boolean); } diff --git a/src/lib/requests/streamPrivacyRequestFiles.ts b/src/lib/requests/streamPrivacyRequestFiles.ts index 4955c13d..35d20a85 100644 --- a/src/lib/requests/streamPrivacyRequestFiles.ts +++ b/src/lib/requests/streamPrivacyRequestFiles.ts @@ -1,8 +1,8 @@ -import { map } from '../bluebird-replace'; import colors from 'colors'; -import { RequestFileMetadata } from './getFileMetadataForPrivacyRequests'; import type { Got } from 'got'; import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; +import { RequestFileMetadata } from './getFileMetadataForPrivacyRequests'; /** * This function will take in a set of file metadata for privacy requests @@ -43,9 +43,11 @@ export async function streamPrivacyRequestFiles( }, }) .buffer() - .then((fileResponse) => onFileDownloaded(metadata, fileResponse)); - } catch (err) { - if (err?.response?.body?.includes('fileMetadata#verify')) { + .then((fileResponse) => { + onFileDownloaded(metadata, fileResponse); + }); + } catch (error) { + if (error?.response?.body?.includes('fileMetadata#verify')) { logger.error( colors.red( `Failed to pull file for: ${metadata.fileName} (request:${requestId}) - JWT expired. ` + @@ -58,7 +60,7 @@ export async function streamPrivacyRequestFiles( } throw new Error( `Received an error from server: ${ - err?.response?.body || err?.message + error?.response?.body || error?.message }`, ); } diff --git a/src/lib/requests/submitPrivacyRequest.ts b/src/lib/requests/submitPrivacyRequest.ts index 90d1a439..ffb7cba7 100644 --- a/src/lib/requests/submitPrivacyRequest.ts +++ b/src/lib/requests/submitPrivacyRequest.ts @@ -1,13 +1,13 @@ -import * as t from 'io-ts'; -import { uniq } from 'lodash-es'; -import { valuesOf, decodeCodec } from '@transcend-io/type-utils'; import { IsoCountryCode, IsoCountrySubdivisionCode, RequestAction, RequestStatus, } from '@transcend-io/privacy-types'; +import { decodeCodec, valuesOf } from '@transcend-io/type-utils'; import type { Got } from 'got'; +import * as t from 'io-ts'; +import { uniq } from 'lodash-es'; import { PrivacyRequestInput } from './mapCsvRowsToRequestInputs'; import { ParsedAttributeInput } from './parseAttributesFromString'; @@ -70,9 +70,9 @@ export async function submitPrivacyRequest( // Merge the per-request attributes with the // global attributes const mergedAttributes = [...additionalAttributes]; - (input.attributes || []).forEach((attribute) => { + for (const attribute of input.attributes || []) { const existing = mergedAttributes.find( - (attr) => attr.key === attribute.key, + (attribute_) => attribute_.key === attribute.key, ); if (existing) { existing.values.push(...attribute.values); @@ -80,7 +80,7 @@ export async function submitPrivacyRequest( } else { mergedAttributes.push(attribute); } - }); + } // Make the GraphQL request let response: unknown; @@ -110,8 +110,8 @@ export async function submitPrivacyRequest( country: input.country, } : input.countrySubDivision - ? { country: input.countrySubDivision.split('-')[0] } - : {}), + ? { country: input.countrySubDivision.split('-')[0] } + : {}), ...(input.countrySubDivision ? { countrySubDivision: input.countrySubDivision } : {}), @@ -124,9 +124,11 @@ export async function submitPrivacyRequest( }, }) .json(); - } catch (err) { + } catch (error) { throw new Error( - `Received an error from server: ${err?.response?.body || err?.message}`, + `Received an error from server: ${ + error?.response?.body || error?.message + }`, ); } diff --git a/src/lib/requests/tests/fuzzyMatchColumns.test.ts b/src/lib/requests/tests/fuzzyMatchColumns.test.ts index 48e7edb1..8c4a8942 100644 --- a/src/lib/requests/tests/fuzzyMatchColumns.test.ts +++ b/src/lib/requests/tests/fuzzyMatchColumns.test.ts @@ -1,6 +1,5 @@ -import { expect, describe, it } from 'vitest'; import inquirer from 'inquirer'; - +import { describe, expect, it } from 'vitest'; import { fuzzyMatchColumns, fuzzySearch, NONE } from '../index'; describe('fuzzyMatchColumns', () => { diff --git a/src/lib/requests/tests/getUniqueValuesForColumn.test.ts b/src/lib/requests/tests/getUniqueValuesForColumn.test.ts index 3c9974d0..7992d1e4 100644 --- a/src/lib/requests/tests/getUniqueValuesForColumn.test.ts +++ b/src/lib/requests/tests/getUniqueValuesForColumn.test.ts @@ -1,5 +1,4 @@ -import { expect, describe, it } from 'vitest'; - +import { describe, expect, it } from 'vitest'; import { getUniqueValuesForColumn } from '../index'; describe('getUniqueValuesForColumn', () => { diff --git a/src/lib/requests/tests/mapCsvRowsToRequestInputs.test.ts b/src/lib/requests/tests/mapCsvRowsToRequestInputs.test.ts index d0916c3a..1c1523f9 100644 --- a/src/lib/requests/tests/mapCsvRowsToRequestInputs.test.ts +++ b/src/lib/requests/tests/mapCsvRowsToRequestInputs.test.ts @@ -1,4 +1,4 @@ import { describe } from 'vitest'; // TODO: https://transcend.height.app/T-10772 - mapCsvRowsToRequestInputs test -describe.skip('mapCsvRowsToRequestInputs', () => undefined); +describe.skip('mapCsvRowsToRequestInputs', () => {}); diff --git a/src/lib/requests/tests/parseAttributesFromString.test.ts b/src/lib/requests/tests/parseAttributesFromString.test.ts index 523af9d0..a1a2466c 100644 --- a/src/lib/requests/tests/parseAttributesFromString.test.ts +++ b/src/lib/requests/tests/parseAttributesFromString.test.ts @@ -1,5 +1,4 @@ -import { expect, describe, it } from 'vitest'; - +import { describe, expect, it } from 'vitest'; import { parseAttributesFromString } from '../index'; describe('parseAttributesFromString', () => { diff --git a/src/lib/requests/tests/readCsv.test.ts b/src/lib/requests/tests/readCsv.test.ts index 03d40299..b3c3ae84 100644 --- a/src/lib/requests/tests/readCsv.test.ts +++ b/src/lib/requests/tests/readCsv.test.ts @@ -1,7 +1,6 @@ -import { expect, describe, it } from 'vitest'; -import { join } from 'path'; +import { join } from 'node:path'; import * as t from 'io-ts'; - +import { describe, expect, it } from 'vitest'; import { readCsv } from '../index'; describe('readCsv', () => { diff --git a/src/lib/requests/tests/splitCsvToList.test.ts b/src/lib/requests/tests/splitCsvToList.test.ts index 72ac8aff..3387d401 100644 --- a/src/lib/requests/tests/splitCsvToList.test.ts +++ b/src/lib/requests/tests/splitCsvToList.test.ts @@ -1,5 +1,4 @@ -import { expect, describe, it } from 'vitest'; - +import { describe, expect, it } from 'vitest'; import { splitCsvToList } from '../index'; describe('splitCsvToList', () => { diff --git a/src/lib/requests/uploadPrivacyRequestsFromCsv.ts b/src/lib/requests/uploadPrivacyRequestsFromCsv.ts index fdd4e5f0..4fc243c5 100644 --- a/src/lib/requests/uploadPrivacyRequestsFromCsv.ts +++ b/src/lib/requests/uploadPrivacyRequestsFromCsv.ts @@ -1,29 +1,28 @@ -/* eslint-disable max-lines */ +import { join } from 'node:path'; +import { PersistedState } from '@transcend-io/persisted-state'; +import cliProgress from 'cli-progress'; import colors from 'colors'; -import { map } from '../bluebird-replace'; import * as t from 'io-ts'; import { uniq } from 'lodash-es'; -import cliProgress from 'cli-progress'; -import { join } from 'path'; -import { PersistedState } from '@transcend-io/persisted-state'; +import { DEFAULT_TRANSCEND_API } from '../../constants'; import { logger } from '../../logger'; +import { map } from '../bluebird-replace'; import { - createSombraGotInstance, buildTranscendGraphQLClient, + createSombraGotInstance, fetchAllRequestAttributeKeys, } from '../graphql'; -import { mapRequestEnumValues } from './mapRequestEnumValues'; -import { CachedRequestState, CachedFileState } from './constants'; +import { CachedFileState, CachedRequestState } from './constants'; +import { extractClientError } from './extractClientError'; +import { filterRows } from './filterRows'; +import { mapColumnsToAttributes } from './mapColumnsToAttributes'; +import { mapColumnsToIdentifiers } from './mapColumnsToIdentifiers'; import { mapCsvColumnsToApi } from './mapCsvColumnsToApi'; +import { mapCsvRowsToRequestInputs } from './mapCsvRowsToRequestInputs'; +import { mapRequestEnumValues } from './mapRequestEnumValues'; import { parseAttributesFromString } from './parseAttributesFromString'; import { readCsv } from './readCsv'; import { submitPrivacyRequest } from './submitPrivacyRequest'; -import { mapColumnsToAttributes } from './mapColumnsToAttributes'; -import { mapColumnsToIdentifiers } from './mapColumnsToIdentifiers'; -import { mapCsvRowsToRequestInputs } from './mapCsvRowsToRequestInputs'; -import { filterRows } from './filterRows'; -import { extractClientError } from './extractClientError'; -import { DEFAULT_TRANSCEND_API } from '../../constants'; /** * Upload a set of privacy requests from CSV @@ -82,7 +81,7 @@ export async function uploadPrivacyRequestsFromCsv({ dryRun?: boolean; }): Promise { // Time duration - const t0 = new Date().getTime(); + const t0 = Date.now(); // create a new progress bar instance and use shades_classic theme const progressBar = new cliProgress.SingleBar( {}, @@ -128,7 +127,7 @@ export async function uploadPrivacyRequestsFromCsv({ // Read in the list of integration requests const requestsList = readCsv(file, t.record(t.string, t.string)); - const columnNames = uniq(requestsList.map((x) => Object.keys(x)).flat()); + const columnNames = uniq(requestsList.flatMap((x) => Object.keys(x))); // Log out an example request if (requestsList.length === 0) { @@ -260,13 +259,13 @@ export async function uploadPrivacyRequestsFromCsv({ attemptedAt: new Date().toISOString(), }); await requestState.setValue(successfulRequests, 'successfulRequests'); - } catch (err) { - const msg = `${err.message} - ${JSON.stringify( - err.response?.body, + } catch (error) { + const message = `${error.message} - ${JSON.stringify( + error.response?.body, null, 2, )}`; - const clientError = extractClientError(msg); + const clientError = extractClientError(message); if ( clientError === 'Client error: You have already made this request.' @@ -292,12 +291,12 @@ export async function uploadPrivacyRequestsFromCsv({ failingRequests.push({ ...requestInput, rowIndex: ind, - error: clientError || msg, + error: clientError || message, attemptedAt: new Date().toISOString(), }); await requestState.setValue(failingRequests, 'failingRequests'); if (debug) { - logger.error(colors.red(clientError || msg)); + logger.error(colors.red(clientError || message)); logger.error( colors.red( `[${ind + 1}/${ @@ -320,7 +319,7 @@ export async function uploadPrivacyRequestsFromCsv({ ); progressBar.stop(); - const t1 = new Date().getTime(); + const t1 = Date.now(); const totalTime = t1 - t0; // Log completion time @@ -353,4 +352,3 @@ export async function uploadPrivacyRequestsFromCsv({ process.exit(1); } } -/* eslint-enable max-lines */ diff --git a/src/lib/tests/TranscendPromptManager.test.ts b/src/lib/tests/TranscendPromptManager.test.ts index 1344ea54..6602618d 100644 --- a/src/lib/tests/TranscendPromptManager.test.ts +++ b/src/lib/tests/TranscendPromptManager.test.ts @@ -1,5 +1,5 @@ -import { expect, describe, it } from 'vitest'; import * as t from 'io-ts'; +import { describe, expect, it } from 'vitest'; import { TranscendPromptManager } from '../ai/TranscendPromptManager'; describe('TranscendPromptManager', () => { diff --git a/src/lib/tests/filterNullValuesFromObject.test.ts b/src/lib/tests/filterNullValuesFromObject.test.ts index e798be5d..d8a43282 100644 --- a/src/lib/tests/filterNullValuesFromObject.test.ts +++ b/src/lib/tests/filterNullValuesFromObject.test.ts @@ -1,5 +1,4 @@ -import { expect, describe, it } from 'vitest'; - +import { describe, expect, it } from 'vitest'; import { filterNullishValuesFromObject } from '../ai/filterNullishValuesFromObject'; const TEST_DATA = { diff --git a/src/lib/tests/findCodePackagesInFolder.test.ts b/src/lib/tests/findCodePackagesInFolder.test.ts index 471f78f6..078f92e3 100644 --- a/src/lib/tests/findCodePackagesInFolder.test.ts +++ b/src/lib/tests/findCodePackagesInFolder.test.ts @@ -1,9 +1,7 @@ -/* eslint-disable max-lines */ -import { expect, describe, it } from 'vitest'; - -import { findCodePackagesInFolder } from '../code-scanning/findCodePackagesInFolder'; -import { join } from 'path'; +import { join } from 'node:path'; +import { describe, expect, it } from 'vitest'; import type { CodePackageInput } from '../../codecs'; +import { findCodePackagesInFolder } from '../code-scanning/findCodePackagesInFolder'; const expected: CodePackageInput[] = [ { @@ -730,4 +728,3 @@ describe('findCodePackagesInFolder', () => { expect(sortCodePackages(result)).to.deep.equal(sortCodePackages(expected)); }); }); -/* eslint-enable max-lines */ diff --git a/src/lib/tests/getGitFilesThatChanged.test.ts b/src/lib/tests/getGitFilesThatChanged.test.ts index fab21808..837126de 100644 --- a/src/lib/tests/getGitFilesThatChanged.test.ts +++ b/src/lib/tests/getGitFilesThatChanged.test.ts @@ -1,7 +1,6 @@ -import { expect, describe, it } from 'vitest'; - +import { join } from 'node:path'; +import { describe, expect, it } from 'vitest'; import { getGitFilesThatChanged } from '../ai/getGitFilesThatChanged'; -import { join } from 'path'; // not easy to test this but can uncomment to run against current commit describe.skip('getGitFilesThatChanged', () => { diff --git a/src/lib/tests/mergeTranscendInputs.test.ts b/src/lib/tests/mergeTranscendInputs.test.ts index 7932cd55..52244b4a 100644 --- a/src/lib/tests/mergeTranscendInputs.test.ts +++ b/src/lib/tests/mergeTranscendInputs.test.ts @@ -1,5 +1,4 @@ -import { expect, describe, it } from 'vitest'; - +import { describe, expect, it } from 'vitest'; import { mergeTranscendInputs, TranscendInput } from '../../index'; describe('mergeTranscendInputs', () => { diff --git a/src/lib/tests/readTranscendYaml.test.ts b/src/lib/tests/readTranscendYaml.test.ts index ffe705c4..050ae708 100644 --- a/src/lib/tests/readTranscendYaml.test.ts +++ b/src/lib/tests/readTranscendYaml.test.ts @@ -1,6 +1,5 @@ -import { expect, describe, it } from 'vitest'; -import { join } from 'path'; - +import { join } from 'node:path'; +import { describe, expect, it } from 'vitest'; import { readTranscendYaml } from '../../index'; const EXAMPLE_DIR = join(__dirname, '..', '..', '..', 'examples'); @@ -35,13 +34,13 @@ describe('readTranscendYaml', () => { stage: 'Staging', }); - expect(result!.enrichers![0].url).to.equal( + expect(result.enrichers![0].url).to.equal( 'https://example.acme.com/transcend-enrichment-webhook', ); - expect(result!.enrichers![1].url).to.equal( + expect(result.enrichers![1].url).to.equal( 'https://example.acme.com/transcend-fraud-check', ); - expect(result!['data-silos']![0].description).to.equal( + expect(result['data-silos']![0].description).to.equal( 'The mega-warehouse that contains a copy over all SQL backed databases - Staging', ); }); diff --git a/src/lib/tests/removeLinks.test.ts b/src/lib/tests/removeLinks.test.ts index 71f80393..63375f1c 100644 --- a/src/lib/tests/removeLinks.test.ts +++ b/src/lib/tests/removeLinks.test.ts @@ -1,5 +1,4 @@ -import { expect, describe, it } from 'vitest'; - +import { describe, expect, it } from 'vitest'; import { removeLinks } from '../ai/removeLinks'; const TEST_DATA = ` diff --git a/vitest.config.ts b/vitest.config.ts index 4a62211c..9ecfec02 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,5 +1,5 @@ -import { defineConfig } from 'vitest/config'; import tsconfigPaths from 'vite-tsconfig-paths'; +import { defineConfig } from 'vitest/config'; export default defineConfig({ plugins: [tsconfigPaths()],