From 8dccfc678da1389431edaacf8b5cd0aa83dd5ce5 Mon Sep 17 00:00:00 2001 From: Cami <50341430+csmccarthy@users.noreply.github.com> Date: Wed, 8 Nov 2023 13:21:04 -0600 Subject: [PATCH] add reserved metadata, reorg exerience vars/types (#104) * add reserved metadata, reorg exerience vars/types --- src/constants.ts | 80 +++++++++++++++++++ src/core.ts | 8 +- src/enums/experience.ts | 165 +--------------------------------------- src/experience.ts | 91 ++++++++++++++++++++++ 4 files changed, 179 insertions(+), 165 deletions(-) create mode 100644 src/experience.ts diff --git a/src/constants.ts b/src/constants.ts index 81e897b..62df234 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -3,6 +3,8 @@ import type { RegimePurposeScopesConfig, TrackingPurpose, } from './core'; +import { BrowserLanguage } from './enums/browserLanguage'; +import { Region } from './experience'; export const UNKNOWN_DEFAULT_EXPERIENCE = 'Unknown'; @@ -39,3 +41,81 @@ export const DEFAULT_EXPERIENCE_PURPOSE_SCOPES = Object.fromEntries( regimes.map((regime) => [regime, purposes]), ).flat(), ); + +// default to [] +export const REGIME_REGIONS: Record = { + CPRA: [{ country: 'US', countrySubDivision: 'US-CA' }], + GDPR: [ + { country: 'EU' }, + { country: 'GB' }, + { country: 'NO' }, + { country: 'IS' }, + { country: 'LI' }, + ], + LGPD: [{ country: 'BR' }], + CDPA: [{ country: 'US', countrySubDivision: 'US-VA' }], + CPA: [{ country: 'US', countrySubDivision: 'US-CO' }], + UCPA: [{ country: 'US', countrySubDivision: 'US-UT' }], + NEVADA_SB220: [{ country: 'US', countrySubDivision: 'US-NV' }], + nFADP: [{ country: 'CH' }], +}; + +// default to [] +export const REGIME_LANGUAGES: Record = { + GDPR: [ + BrowserLanguage['Bulgarian (Bulgaria)'], + BrowserLanguage['Croatian (Croatia)'], + BrowserLanguage['Czech (Czech Republic)'], + BrowserLanguage['Danish (Denmark)'], + BrowserLanguage['Dutch (Belgium)'], + BrowserLanguage['Dutch (Netherlands)'], + BrowserLanguage['English (Ireland)'], + BrowserLanguage['Estonian (Estonia)'], + BrowserLanguage['Finnish (Finland)'], + BrowserLanguage['French (Belgium)'], + BrowserLanguage['French (France)'], + BrowserLanguage['French (Luxembourg)'], + BrowserLanguage['German (Austria)'], + BrowserLanguage['German (Germany)'], + BrowserLanguage['German (Liechtenstein)'], + BrowserLanguage['German (Luxembourg)'], + BrowserLanguage['Greek (Greece)'], + BrowserLanguage['Hungarian (Hungary)'], + BrowserLanguage['Icelandic (Iceland)'], + BrowserLanguage['Irish (Ireland)'], + BrowserLanguage['Italian (Italy)'], + BrowserLanguage['Latvian (Latvia)'], + BrowserLanguage['Lithuanian (Lithuania)'], + BrowserLanguage['Maltese (Malta)'], + BrowserLanguage['Norwegian (Norway)'], + BrowserLanguage['Norwegian Bokmål (Norway)'], + BrowserLanguage['Norwegian Nynorsk (Norway)'], + BrowserLanguage['Polish (Poland)'], + BrowserLanguage['Portuguese (Portugal)'], + BrowserLanguage['Romanian (Romania)'], + BrowserLanguage['Slovak (Slovakia)'], + BrowserLanguage['Slovenian (Slovenia)'], + BrowserLanguage['Spanish (Espa\u00f1a)'], + BrowserLanguage['Swedish (Finland)'], + BrowserLanguage['Swedish (Finland)'], + BrowserLanguage['Swedish (Sweden)'], + ], + LGPD: [BrowserLanguage['Portuguese (Brazil)']], + nFADP: [ + BrowserLanguage['German (Switzerland)'], + BrowserLanguage['French (Switzerland)'], + BrowserLanguage['Italian (Switzerland)'], + BrowserLanguage['English (Switzerland)'], + BrowserLanguage['Portuguese (Switzerland)'], + BrowserLanguage['Swiss German (Switzerland)'], + ], +}; + +// default to [] +export const REGIME_TIMEZONES: Record = {}; + +// default to 20 +export const REGIME_DISPLAY_PRIORITY: Record = { + GDPR: 10, + Unknown: 100, +}; diff --git a/src/core.ts b/src/core.ts index d7cba5f..c75bffb 100644 --- a/src/core.ts +++ b/src/core.ts @@ -124,6 +124,12 @@ export interface GetPurposeTypesOptions { */ export type RegimeToPurposeScopes = [PrivacyRegime[], TrackingPurpose[]][]; +/** Reserved metadata, currently used for airgap module data syncing */ +export interface ReservedMetadata { + /** Top-level key to avoid polluting the metadata key space */ + tcmp: null | Record; +} + /** setConsent() options */ export interface ConsentOptions { /** Was consent confirmed by the user? */ @@ -137,7 +143,7 @@ export interface ConsentOptions { * - `null` - Do not change metadata * - `false` - Clear metadata */ - metadata?: Record | null | false; + metadata?: (Record & ReservedMetadata) | null | false; /** Last updated for metadata */ metadataTimestamp?: string; /** Whether or not to return a Promise so that the caller can wait for sync to complete. By default, we do not wait for sync */ diff --git a/src/enums/experience.ts b/src/enums/experience.ts index e992675..02a9a88 100644 --- a/src/enums/experience.ts +++ b/src/enums/experience.ts @@ -1,110 +1,5 @@ // main -import { applyEnum, makeEnum } from '@transcend-io/type-utils'; -import { IsoCountryCode } from '@transcend-io/privacy-types'; - -// local -import { PrivacyRegimeEnum } from './privacyRegime'; -import { Purpose } from './purpose'; -import { InitialViewState } from './viewState'; -import { DEFAULT_VIEW_STATE_BY_PRIVACY_REGIME } from '../ui'; -import { PrivacyRegime } from '../core'; -import { - DEFAULT_EXPERIENCE_PURPOSE_SCOPES, - DEFAULT_EXPERIENCE_PURPOSE_OPT_OUTS, -} from '../constants'; -import { BrowserLanguage } from './browserLanguage'; - -export interface Region { - /** A country's ISO code */ - country: IsoCountryCode; - /** A country subdivision ISO code */ - countrySubDivision?: string; -} - -export interface ExperiencePurposeInput { - /** name of the purpose */ - purpose: Purpose; - /** opt out by default */ - defaultOptOut: boolean; -} - -// default to [] -export const REGIME_REGIONS: Record = { - CPRA: [{ country: 'US', countrySubDivision: 'US-CA' }], - GDPR: [ - { country: 'EU' }, - { country: 'GB' }, - { country: 'NO' }, - { country: 'IS' }, - { country: 'LI' }, - ], - LGPD: [{ country: 'BR' }], - CDPA: [{ country: 'US', countrySubDivision: 'US-VA' }], - CPA: [{ country: 'US', countrySubDivision: 'US-CO' }], - UCPA: [{ country: 'US', countrySubDivision: 'US-UT' }], - NEVADA_SB220: [{ country: 'US', countrySubDivision: 'US-NV' }], - nFADP: [{ country: 'CH' }], -}; - -// default to [] -export const REGIME_LANGUAGES: Record = { - GDPR: [ - BrowserLanguage['Bulgarian (Bulgaria)'], - BrowserLanguage['Croatian (Croatia)'], - BrowserLanguage['Czech (Czech Republic)'], - BrowserLanguage['Danish (Denmark)'], - BrowserLanguage['Dutch (Belgium)'], - BrowserLanguage['Dutch (Netherlands)'], - BrowserLanguage['English (Ireland)'], - BrowserLanguage['Estonian (Estonia)'], - BrowserLanguage['Finnish (Finland)'], - BrowserLanguage['French (Belgium)'], - BrowserLanguage['French (France)'], - BrowserLanguage['French (Luxembourg)'], - BrowserLanguage['German (Austria)'], - BrowserLanguage['German (Germany)'], - BrowserLanguage['German (Liechtenstein)'], - BrowserLanguage['German (Luxembourg)'], - BrowserLanguage['Greek (Greece)'], - BrowserLanguage['Hungarian (Hungary)'], - BrowserLanguage['Icelandic (Iceland)'], - BrowserLanguage['Irish (Ireland)'], - BrowserLanguage['Italian (Italy)'], - BrowserLanguage['Latvian (Latvia)'], - BrowserLanguage['Lithuanian (Lithuania)'], - BrowserLanguage['Maltese (Malta)'], - BrowserLanguage['Norwegian (Norway)'], - BrowserLanguage['Norwegian Bokmål (Norway)'], - BrowserLanguage['Norwegian Nynorsk (Norway)'], - BrowserLanguage['Polish (Poland)'], - BrowserLanguage['Portuguese (Portugal)'], - BrowserLanguage['Romanian (Romania)'], - BrowserLanguage['Slovak (Slovakia)'], - BrowserLanguage['Slovenian (Slovenia)'], - BrowserLanguage['Spanish (Espa\u00f1a)'], - BrowserLanguage['Swedish (Finland)'], - BrowserLanguage['Swedish (Finland)'], - BrowserLanguage['Swedish (Sweden)'], - ], - LGPD: [BrowserLanguage['Portuguese (Brazil)']], - nFADP: [ - BrowserLanguage['German (Switzerland)'], - BrowserLanguage['French (Switzerland)'], - BrowserLanguage['Italian (Switzerland)'], - BrowserLanguage['English (Switzerland)'], - BrowserLanguage['Portuguese (Switzerland)'], - BrowserLanguage['Swiss German (Switzerland)'], - ], -}; - -// default to [] -export const REGIME_TIMEZONES: Record = {}; - -// default to 20 -export const REGIME_DISPLAY_PRIORITY: Record = { - GDPR: 10, - Unknown: 100, -}; +import { makeEnum } from '@transcend-io/type-utils'; /** * Describes whether listed countries/country subdivisions are included in an experience @@ -118,61 +13,3 @@ export const RegionsOperator = makeEnum({ /** Override type */ export type RegionsOperator = typeof RegionsOperator[keyof typeof RegionsOperator]; - -export interface ExperienceInput { - /** The regime determining the default experience */ - name: PrivacyRegime; - /** The display name of the experience */ - displayName: string; - /** A list of regions to be included/not included in this experience */ - regions: Region[]; - /** A list of browser languages that this experience applies to */ - browserLanguages: string[]; - /** A list of browser time zones that this experience applies to */ - browserTimeZones: string[]; - /** Whether the listed regions are included or excluded from the experience */ - operator: RegionsOperator; - /** If data subject linked to multiple experiences, display priority for experiences. Lower number, higher priority. */ - displayPriority: number; - /** The view state to display on transcend.showConsentManager() */ - viewState: InitialViewState; - /** experience purposes to be added */ - experiencePurposeInputs: ExperiencePurposeInput[]; -} - -/** - * construct default experience for regime - * - * @param regime - regime - * @returns ExperienceInput - */ -export function defaultExperience(regime: PrivacyRegime): ExperienceInput { - const isUnknown = regime === 'Unknown'; - const regimeEnum = - PrivacyRegimeEnum[regime as keyof typeof PrivacyRegimeEnum]; - return { - name: regime, - displayName: regime, - regions: REGIME_REGIONS[regime] ?? [], - operator: isUnknown ? RegionsOperator.NotIn : RegionsOperator.In, - displayPriority: REGIME_DISPLAY_PRIORITY[regime] ?? 20, - viewState: - DEFAULT_VIEW_STATE_BY_PRIVACY_REGIME[regimeEnum] ?? - InitialViewState.Hidden, - browserLanguages: REGIME_LANGUAGES[regime] ?? [], - browserTimeZones: REGIME_TIMEZONES[regime] ?? [], - experiencePurposeInputs: DEFAULT_EXPERIENCE_PURPOSE_SCOPES[regime].map( - (purpose: Purpose) => ({ - purpose, - defaultOptOut: - DEFAULT_EXPERIENCE_PURPOSE_OPT_OUTS[regime]?.includes(purpose) ?? - false, - }), - ), - }; -} - -export const DEFAULT_EXPERIENCES = applyEnum( - PrivacyRegimeEnum, - defaultExperience, -); diff --git a/src/experience.ts b/src/experience.ts new file mode 100644 index 0000000..d070b3d --- /dev/null +++ b/src/experience.ts @@ -0,0 +1,91 @@ +// main +import { applyEnum } from '@transcend-io/type-utils'; +import { IsoCountryCode } from '@transcend-io/privacy-types'; + +// local +import { PrivacyRegimeEnum } from './enums/privacyRegime'; +import { Purpose } from './enums/purpose'; +import { InitialViewState } from './enums/viewState'; +import { DEFAULT_VIEW_STATE_BY_PRIVACY_REGIME } from './ui'; +import { PrivacyRegime } from './core'; +import { + DEFAULT_EXPERIENCE_PURPOSE_SCOPES, + DEFAULT_EXPERIENCE_PURPOSE_OPT_OUTS, + REGIME_REGIONS, + REGIME_DISPLAY_PRIORITY, + REGIME_LANGUAGES, + REGIME_TIMEZONES, +} from './constants'; +import { RegionsOperator } from './enums'; + +export interface Region { + /** A country's ISO code */ + country: IsoCountryCode; + /** A country subdivision ISO code */ + countrySubDivision?: string; +} + +export interface ExperiencePurposeInput { + /** name of the purpose */ + purpose: Purpose; + /** opt out by default */ + defaultOptOut: boolean; +} + +export interface ExperienceInput { + /** The regime determining the default experience */ + name: PrivacyRegime; + /** The display name of the experience */ + displayName: string; + /** A list of regions to be included/not included in this experience */ + regions: Region[]; + /** A list of browser languages that this experience applies to */ + browserLanguages: string[]; + /** A list of browser time zones that this experience applies to */ + browserTimeZones: string[]; + /** Whether the listed regions are included or excluded from the experience */ + operator: RegionsOperator; + /** If data subject linked to multiple experiences, display priority for experiences. Lower number, higher priority. */ + displayPriority: number; + /** The view state to display on transcend.showConsentManager() */ + viewState: InitialViewState; + /** experience purposes to be added */ + experiencePurposeInputs: ExperiencePurposeInput[]; +} + +/** + * construct default experience for regime + * + * @param regime - regime + * @returns ExperienceInput + */ +export function defaultExperience(regime: PrivacyRegime): ExperienceInput { + const isUnknown = regime === 'Unknown'; + const regimeEnum = + PrivacyRegimeEnum[regime as keyof typeof PrivacyRegimeEnum]; + return { + name: regime, + displayName: regime, + regions: REGIME_REGIONS[regime] ?? [], + operator: isUnknown ? RegionsOperator.NotIn : RegionsOperator.In, + displayPriority: REGIME_DISPLAY_PRIORITY[regime] ?? 20, + viewState: + DEFAULT_VIEW_STATE_BY_PRIVACY_REGIME[regimeEnum] ?? + InitialViewState.Hidden, + browserLanguages: REGIME_LANGUAGES[regime] ?? [], + browserTimeZones: REGIME_TIMEZONES[regime] ?? [], + experiencePurposeInputs: DEFAULT_EXPERIENCE_PURPOSE_SCOPES[regime].map( + (purpose: Purpose) => ({ + purpose, + defaultOptOut: + DEFAULT_EXPERIENCE_PURPOSE_OPT_OUTS[regime]?.includes(purpose) ?? + false, + }), + ), + }; +} + +export const DEFAULT_EXPERIENCES = applyEnum( + PrivacyRegimeEnum, + defaultExperience, +);