diff --git a/src/enrichers/cache.ts b/src/enrichers/cache.ts deleted file mode 100644 index cd324eb7..00000000 --- a/src/enrichers/cache.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { EventBus, strEqualsIgnoreCase } from 'live-connect-common' -import { DurableCache, NoOpCache, StorageHandlerBackedCache } from '../cache' -import { WrappedStorageHandler } from '../handlers/storage-handler' -import { StorageStrategies, StorageStrategy } from '../model/storage-strategy' -import { Enricher } from '../types' - -type Input = { domain: string, storageHandler: WrappedStorageHandler, eventBus: EventBus, storageStrategy: StorageStrategy } -type Output = { cache: DurableCache } - -export const enrichCache: Enricher = state => { - let cache - - if (strEqualsIgnoreCase(state.storageStrategy, StorageStrategies.none)) { - cache = NoOpCache - } else { - cache = new StorageHandlerBackedCache({ - storageHandler: state.storageHandler, - domain: state.domain, - eventBus: state.eventBus - }) - } - return { ...state, cache } -} diff --git a/src/enrichers/decisions.ts b/src/enrichers/decisions.ts index e19ffad2..7f0a5304 100644 --- a/src/enrichers/decisions.ts +++ b/src/enrichers/decisions.ts @@ -1,13 +1,74 @@ import { Enricher, EventBus } from '../types' +import { getQueryParameter, ParsedParam } from '../utils/url' +import { trim, isUUID, expiresInDays } from 'live-connect-common' import { WrappedStorageHandler } from '../handlers/storage-handler' -import { resolve } from '../manager/decisions' type Input = { pageUrl?: string, domain: string } type Output = { decisionIds: string[] } +const DEFAULT_DECISION_ID_COOKIE_EXPIRES = expiresInDays(30) +const DECISION_ID_QUERY_PARAM_NAME = 'li_did' +const DECISION_ID_COOKIE_NAMESPACE = 'lidids.' + +const _onlyUnique = (value: string, index: number, self: string[]) => self.indexOf(value) === index +const _nonEmpty = (value: string) => value && trim(value).length > 0 + export function enrichDecisionIds( storageHandler: WrappedStorageHandler, eventBus: EventBus ): Enricher { - return state => ({ ...state, ...resolve(state, storageHandler, eventBus) }) + return state => { + function _addDecisionId(key: string, cookieDomain?: string) { + if (key) { + storageHandler.setCookie( + `${DECISION_ID_COOKIE_NAMESPACE}${key}`, + key, + DEFAULT_DECISION_ID_COOKIE_EXPIRES, + 'Lax', + cookieDomain) + } + } + + function _orElseEmpty(errorDescription: string, f: () => A[]): A[] { + try { + return f() + } catch (e) { + eventBus.emitErrorWithMessage('DecisionsResolve', errorDescription, e) + return [] + } + } + + const freshDecisions = _orElseEmpty( + 'Error while extracting new decision ids', + () => { + const extractedFreshDecisions = ([] as ParsedParam[]).concat((state.pageUrl && getQueryParameter(state.pageUrl, DECISION_ID_QUERY_PARAM_NAME)) || []) + return extractedFreshDecisions + .map(trim) + .filter(_nonEmpty) + .filter(isUUID) + .filter(_onlyUnique) + } + ) + + const storedDecisions = _orElseEmpty( + 'Error while retrieving stored decision ids', + () => { + const extractedStoredDecisions = storageHandler.findSimilarCookies(DECISION_ID_COOKIE_NAMESPACE) + return extractedStoredDecisions + .map(trim) + .filter(_nonEmpty) + .filter(isUUID) + } + ) + + freshDecisions.forEach(decision => { + try { + _addDecisionId(decision, state.domain) + } catch (e) { + eventBus.emitErrorWithMessage('DecisionsResolve', 'Error while storing new decision id', e) + } + }) + + return { ...state, decisionIds: freshDecisions.concat(storedDecisions).filter(_onlyUnique) } + } } diff --git a/src/manager/decisions.ts b/src/manager/decisions.ts deleted file mode 100644 index ba6f2a96..00000000 --- a/src/manager/decisions.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { getQueryParameter, ParsedParam } from '../utils/url' -import { trim, isUUID, expiresInDays } from 'live-connect-common' -import { EventBus } from '../types' -import { WrappedStorageHandler } from '../handlers/storage-handler' - -const DEFAULT_DECISION_ID_COOKIE_EXPIRES = expiresInDays(30) -const DECISION_ID_QUERY_PARAM_NAME = 'li_did' -const DECISION_ID_COOKIE_NAMESPACE = 'lidids.' - -const _onlyUnique = (value: string, index: number, self: string[]) => self.indexOf(value) === index -const _nonEmpty = (value: string) => value && trim(value).length > 0 - -export function resolve(state: { pageUrl?: string, domain?: string }, storageHandler: WrappedStorageHandler, eventBus: EventBus): { decisionIds: string[] } { - function _addDecisionId(key: string, cookieDomain?: string) { - if (key) { - storageHandler.setCookie( - `${DECISION_ID_COOKIE_NAMESPACE}${key}`, - key, - DEFAULT_DECISION_ID_COOKIE_EXPIRES, - 'Lax', - cookieDomain) - } - } - - function _orElseEmpty(errorDescription: string, f: () => A[]): A[] { - try { - return f() - } catch (e) { - eventBus.emitErrorWithMessage('DecisionsResolve', errorDescription, e) - return [] - } - } - - const freshDecisions = _orElseEmpty( - 'Error while extracting new decision ids', - () => { - const extractedFreshDecisions = ([] as ParsedParam[]).concat((state.pageUrl && getQueryParameter(state.pageUrl, DECISION_ID_QUERY_PARAM_NAME)) || []) - return extractedFreshDecisions - .map(trim) - .filter(_nonEmpty) - .filter(isUUID) - .filter(_onlyUnique) - } - ) - - const storedDecisions = _orElseEmpty( - 'Error while retrieving stored decision ids', - () => { - const extractedStoredDecisions = storageHandler.findSimilarCookies(DECISION_ID_COOKIE_NAMESPACE) - return extractedStoredDecisions - .map(trim) - .filter(_nonEmpty) - .filter(isUUID) - } - ) - - freshDecisions.forEach(decision => { - try { - _addDecisionId(decision, state.domain) - } catch (e) { - eventBus.emitErrorWithMessage('DecisionsResolve', 'Error while storing new decision id', e) - } - }) - - return { decisionIds: freshDecisions.concat(storedDecisions).filter(_onlyUnique) } -} diff --git a/src/pixel/fiddler.ts b/src/pixel/fiddler.ts index b1f2d5c3..f2608824 100644 --- a/src/pixel/fiddler.ts +++ b/src/pixel/fiddler.ts @@ -1,4 +1,4 @@ -import { Enricher, State } from '../types' +import { State } from '../types' import { extractEmail } from '../utils/email' import { decodeValue } from '../utils/url' import { extractHashValue, hashEmail, isHash } from '../utils/hash' @@ -75,15 +75,3 @@ export function mergeObjects(obj1: A, obj2: }) return res } - -export class EnrichmentContext { - data: A - - constructor (state: A) { - this.data = state - } - - via(enricher: Enricher): EnrichmentContext { - return new EnrichmentContext({ ...this.data, ...enricher(this.data) }) - } -} diff --git a/test/unit/manager/decisions.spec.ts b/test/unit/enricher/decisions.spec.ts similarity index 76% rename from test/unit/manager/decisions.spec.ts rename to test/unit/enricher/decisions.spec.ts index 4efd9bf5..ac6567c3 100644 --- a/test/unit/manager/decisions.spec.ts +++ b/test/unit/enricher/decisions.spec.ts @@ -1,5 +1,5 @@ import { expect, use } from 'chai' -import * as decisions from '../../../src/manager/decisions' +import { enrichDecisionIds } from '../../../src/enrichers/decisions' import { DefaultStorageHandler } from 'live-connect-handlers' // @ts-expect-error import uuid from 'tiny-uuid4' @@ -18,6 +18,8 @@ describe('DecisionsManager for stored decisions', () => { let externalStorage: DefaultStorageHandler let storage: WrappedStorageHandler + const domain = 'example.com' + beforeEach(() => { eventBus = LocalEventBus() externalStorage = new DefaultStorageHandler(eventBus) @@ -29,26 +31,26 @@ describe('DecisionsManager for stored decisions', () => { }) it('should return an empty string if nothing is in the cookie jar', () => { - const resolutionResult = decisions.resolve({}, storage, eventBus) + const resolutionResult = enrichDecisionIds(storage, eventBus)({ domain }) expect(resolutionResult.decisionIds).to.eql([]) }) it('should return an empty string if the cookie jar has invalid uuids', () => { storage.setCookie('lidids.', '2134') - const resolutionResult = decisions.resolve({}, storage, eventBus) + const resolutionResult = enrichDecisionIds(storage, eventBus)({ domain }) expect(resolutionResult.decisionIds).to.eql([]) }) it('should return the stored decision', () => { const decisionId = uuid() storage.setCookie('lidids.123', decisionId) - const resolutionResult = decisions.resolve({}, storage, eventBus) + const resolutionResult = enrichDecisionIds(storage, eventBus)({ domain }) expect(resolutionResult.decisionIds).to.eql([decisionId]) }) it('should not return empty values', () => { storage.setCookie('lidids.', '') - const resolutionResult = decisions.resolve({}, storage, eventBus) + const resolutionResult = enrichDecisionIds(storage, eventBus)({ domain }) expect(resolutionResult.decisionIds.length).to.eql(0) }) @@ -56,7 +58,7 @@ describe('DecisionsManager for stored decisions', () => { const decisionId = uuid() storage.setCookie('lidids.123', decisionId, undefined, undefined, 'something.example.com') storage.setCookie('lidids.123', decisionId, undefined, undefined, 'www.something.example.com') - const resolutionResult = decisions.resolve({}, storage, eventBus) + const resolutionResult = enrichDecisionIds(storage, eventBus)({ domain }) expect(resolutionResult.decisionIds).to.eql([decisionId]) }) }) @@ -67,6 +69,8 @@ describe('DecisionsManager for new decisions', () => { let externalStorage: DefaultStorageHandler let storage: WrappedStorageHandler + const domain = 'example.com' + beforeEach(() => { sandbox = sinon.createSandbox() eventBus = LocalEventBus() @@ -80,21 +84,21 @@ describe('DecisionsManager for new decisions', () => { it('should return the new decision id, and store it', () => { const decisionId = uuid() - const resolutionResult = decisions.resolve({ pageUrl: `http://subdomain.tests.example.com/cake?li_did=${decisionId}` }, storage, eventBus) + const resolutionResult = enrichDecisionIds(storage, eventBus)({ domain, pageUrl: `http://subdomain.tests.example.com/cake?li_did=${decisionId}` }) expect(resolutionResult.decisionIds).to.eql([decisionId]) expect(storage.getCookie(`lidids.${decisionId}`)).to.eq(decisionId) }) it('should return the new decision id, and store it', () => { const decisionId = uuid() - const resolutionResult = decisions.resolve({ pageUrl: `http://subdomain.tests.example.com/cake?li_did=${decisionId}` }, storage, eventBus) + const resolutionResult = enrichDecisionIds(storage, eventBus)({ domain, pageUrl: `http://subdomain.tests.example.com/cake?li_did=${decisionId}` }) expect(resolutionResult.decisionIds).to.eql([decisionId]) expect(storage.getCookie(`lidids.${decisionId}`)).to.eq(decisionId) }) it('should not return the new decision id if its not a uuid', () => { const decisionId = `${uuid()}sometghing` - const resolutionResult = decisions.resolve({ pageUrl: `http://subdomain.tests.example.com/cake?li_did=${decisionId}` }, storage, eventBus) + const resolutionResult = enrichDecisionIds(storage, eventBus)({ domain, pageUrl: `http://subdomain.tests.example.com/cake?li_did=${decisionId}` }) expect(resolutionResult.decisionIds).to.eql([]) }) @@ -102,7 +106,7 @@ describe('DecisionsManager for new decisions', () => { const decisionIdOne = uuid() const decisionIdTwo = uuid() storage.setCookie('lidids.123', decisionIdOne) - const resolutionResult = decisions.resolve({ pageUrl: `http://subdomain.tests.example.com/cake?li_did= ${decisionIdTwo}` }, storage, eventBus) + const resolutionResult = enrichDecisionIds(storage, eventBus)({ domain, pageUrl: `http://subdomain.tests.example.com/cake?li_did= ${decisionIdTwo}` }) expect(resolutionResult.decisionIds).to.eql([decisionIdTwo, decisionIdOne]) expect(storage.getCookie(`lidids.${decisionIdTwo}`)).to.eq(decisionIdTwo) }) @@ -112,7 +116,7 @@ describe('DecisionsManager for new decisions', () => { const decisionIdTwo = uuid() const decisionIdThree = uuid() storage.setCookie('lidids.123', decisionIdOne) - const resolutionResult = decisions.resolve({ pageUrl: `http://subdomain.tests.example.com/cake?li_did=${decisionIdTwo}&li_did=${decisionIdThree}` }, storage, eventBus) + const resolutionResult = enrichDecisionIds(storage, eventBus)({ domain, pageUrl: `http://subdomain.tests.example.com/cake?li_did=${decisionIdTwo}&li_did=${decisionIdThree}` }) expect(resolutionResult.decisionIds).to.eql([decisionIdTwo, decisionIdThree, decisionIdOne]) expect(storage.getCookie(`lidids.${decisionIdTwo}`)).to.eq(decisionIdTwo) expect(storage.getCookie(`lidids.${decisionIdThree}`)).to.eq(decisionIdThree) @@ -133,7 +137,7 @@ describe('DecisionsManager for new decisions', () => { stub => stub.restore(), () => { expect(errorEmitted).to.eq(false) - const resolutionResult = decisions.resolve({ pageUrl: `http://subdomain.tests.example.com/cake?li_did=${decisionIdTwo}&li_did=${decisionIdThree}` }, storage, eventBus) + const resolutionResult = enrichDecisionIds(storage, eventBus)({ domain, pageUrl: `http://subdomain.tests.example.com/cake?li_did=${decisionIdTwo}&li_did=${decisionIdThree}` }) expect(resolutionResult.decisionIds).to.eql([decisionIdTwo, decisionIdThree]) expect(storage.getCookie(`lidids.${decisionIdTwo}`)).to.eq(decisionIdTwo) expect(storage.getCookie(`lidids.${decisionIdThree}`)).to.eq(decisionIdThree) @@ -156,7 +160,7 @@ describe('DecisionsManager for new decisions', () => { stub => stub.restore(), () => { expect(errorEmitted).to.eq(false) - const resolutionResult = decisions.resolve({ pageUrl: `http://subdomain.tests.example.com/cake?li_did=${decisionIdTwo}&li_did=${decisionIdThree}` }, storage, eventBus) + const resolutionResult = enrichDecisionIds(storage, eventBus)({ domain, pageUrl: `http://subdomain.tests.example.com/cake?li_did=${decisionIdTwo}&li_did=${decisionIdThree}` }) expect(resolutionResult.decisionIds).to.eql([decisionIdTwo, decisionIdThree, decisionIdOne]) expect(errorEmitted).to.eq(true) })