diff --git a/src/__tests__/autocapture.js b/src/__tests__/autocapture.js index aa8c9ef26..0fc7dbdbf 100644 --- a/src/__tests__/autocapture.js +++ b/src/__tests__/autocapture.js @@ -3,7 +3,7 @@ import sinon from 'sinon' import { autocapture } from '../autocapture' import { shouldCaptureDomEvent } from '../autocapture-utils' -import { AUTOCAPTURE_DISABLED_SERVER_SIDE } from '../posthog-persistence' +import { AUTOCAPTURE_DISABLED_SERVER_SIDE } from '../constants' const triggerMouseEvent = function (node, eventType) { node.dispatchEvent( diff --git a/src/__tests__/compression.js b/src/__tests__/compression.js index ce779e7d1..3f0f72f3b 100644 --- a/src/__tests__/compression.js +++ b/src/__tests__/compression.js @@ -2,7 +2,7 @@ import sinon from 'sinon' import { autocapture } from '../autocapture' import { decideCompression, compressData } from '../compression' import { Decide } from '../decide' -import { AUTOCAPTURE_DISABLED_SERVER_SIDE } from '../posthog-persistence' +import { AUTOCAPTURE_DISABLED_SERVER_SIDE } from '../constants' describe('decideCompression()', () => { given('subject', () => decideCompression(given.compressionSupport)) diff --git a/src/__tests__/extensions/sessionrecording.js b/src/__tests__/extensions/sessionrecording.js index 2a90eaebf..603cd02fb 100644 --- a/src/__tests__/extensions/sessionrecording.js +++ b/src/__tests__/extensions/sessionrecording.js @@ -4,11 +4,8 @@ import { RECORDING_MAX_EVENT_SIZE, SessionRecording, } from '../../extensions/sessionrecording' -import { - PostHogPersistence, - SESSION_RECORDING_ENABLED_SERVER_SIDE, - SESSION_RECORDING_RECORDER_VERSION_SERVER_SIDE, -} from '../../posthog-persistence' +import { PostHogPersistence } from '../../posthog-persistence' +import { SESSION_RECORDING_ENABLED_SERVER_SIDE, SESSION_RECORDING_RECORDER_VERSION_SERVER_SIDE } from '../../constants' import { SessionIdManager } from '../../sessionid' import { INCREMENTAL_SNAPSHOT_EVENT_TYPE, diff --git a/src/__tests__/gdpr-utils.js b/src/__tests__/gdpr-utils.js index bed72a8cb..c8b02e2cc 100644 --- a/src/__tests__/gdpr-utils.js +++ b/src/__tests__/gdpr-utils.js @@ -10,6 +10,17 @@ const TOKENS = [ const DEFAULT_PERSISTENCE_PREFIX = `__ph_opt_in_out_` const CUSTOM_PERSISTENCE_PREFIX = `𝓶𝓶𝓶𝓬𝓸𝓸𝓴𝓲𝓮𝓼` +function deleteAllCookies() { + var cookies = document.cookie.split(';') + + for (var i = 0; i < cookies.length; i++) { + var cookie = cookies[i] + var eqPos = cookie.indexOf('=') + var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie + document.cookie = name + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT' + } +} + function forPersistenceTypes(runTests) { ;[`cookie`, `localStorage`, `localStorage+cookie`].forEach(function (persistenceType) { describe(persistenceType, runTests.bind(null, persistenceType)) @@ -31,16 +42,7 @@ function assertPersistenceValue(persistenceType, token, value, persistencePrefix } } } -function deleteAllCookies() { - var cookies = document.cookie.split(';') - for (var i = 0; i < cookies.length; i++) { - var cookie = cookies[i] - var eqPos = cookie.indexOf('=') - var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie - document.cookie = name + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT' - } -} describe(`GDPR utils`, () => { // these imports must be re-required before each test // so that they reference the correct jsdom document diff --git a/src/__tests__/posthog-persistence.js b/src/__tests__/posthog-persistence.js index e68e663b8..cfb4760dd 100644 --- a/src/__tests__/posthog-persistence.js +++ b/src/__tests__/posthog-persistence.js @@ -1,129 +1,158 @@ import { PostHogPersistence } from '../posthog-persistence' +import { SESSION_ID, USER_STATE } from '../constants' given('lib', () => new PostHogPersistence({ name: 'bla', persistence: 'cookie' })) -function forPersistenceTypes(runTests) { - ;[`cookie`, `localStorage`, `localStorage+cookie`].forEach(function (persistenceType) { - describe(persistenceType, runTests.bind(null, persistenceType)) - }) -} - let referrer = '' // No referrer by default Object.defineProperty(document, 'referrer', { get: () => referrer }) describe('persistence', () => { afterEach(() => { given.lib.clear() + document.cookie = '' referrer = '' }) - it('should set direct referrer', () => { - referrer = '' - given.lib.update_referrer_info() - - expect(given.lib.props['$referring_domain']).toBe('$direct') - expect(given.lib.props['$referrer']).toBe('$direct') - }) + describe.each([`cookie`, `localStorage`, `localStorage+cookie`])('persistence modes: %p', (persistenceMode) => { + // Common tests for all storage modes + beforeEach(() => { + given('lib', () => new PostHogPersistence({ name: 'test', persistence: persistenceMode })) + given.lib.clear() + }) - it('should set external referrer', () => { - referrer = 'https://www.google.com' - given.lib.update_referrer_info() + it('should register_once', () => { + given.lib.register_once({ distinct_id: 'hi', test_prop: 'test_val' }) - expect(given.lib.props['$referring_domain']).toBe('www.google.com') - expect(given.lib.props['$referrer']).toBe('https://www.google.com') - }) + let lib2 = new PostHogPersistence({ name: 'test', persistence: persistenceMode }) + expect(lib2.props).toEqual({ distinct_id: 'hi', test_prop: 'test_val' }) + }) - it('should set internal referrer', () => { - referrer = 'https://hedgebox.net/files/abc.png' - given.lib.update_referrer_info() + it('should save user state', () => { + let lib = new PostHogPersistence({ name: 'bla', persistence: 'cookie' }) + lib.set_user_state('identified') + expect(lib.props[USER_STATE]).toEqual('identified') + }) - expect(given.lib.props['$referring_domain']).toBe('hedgebox.net') - expect(given.lib.props['$referrer']).toBe('https://hedgebox.net/files/abc.png') - }) + it('can load user state', () => { + let lib = new PostHogPersistence({ name: 'bla', persistence: 'cookie' }) + lib.set_user_state('identified') + expect(lib.get_user_state()).toEqual('identified') + }) - it('extracts enabled feature flags', () => { - given.lib.register({ $enabled_feature_flags: { flag: 'variant', other: true } }) - expect(given.lib.props['$enabled_feature_flags']).toEqual({ flag: 'variant', other: true }) - expect(given.lib.properties()).toEqual({ - '$feature/flag': 'variant', - '$feature/other': true, + it('has user state as a reserved property key', () => { + let lib = new PostHogPersistence({ name: 'bla', persistence: 'cookie' }) + lib.register({ distinct_id: 'testy', test_prop: 'test_value' }) + lib.set_user_state('identified') + expect(lib.properties()).toEqual({ distinct_id: 'testy', test_prop: 'test_value' }) }) - }) - it('should migrate data from cookies to localStorage', () => { - let lib = new PostHogPersistence({ name: 'bla', persistence: 'cookie' }) - lib.register_once({ distinct_id: 'testy', test_prop: 'test_value' }) - expect(document.cookie).toEqual( - 'ph__posthog=%7B%22distinct_id%22%3A%22testy%22%2C%22test_prop%22%3A%22test_value%22%7D' - ) - let lib2 = new PostHogPersistence({ name: 'bla', persistence: 'localStorage+cookie' }) - expect(document.cookie).toEqual('ph__posthog=%7B%22distinct_id%22%3A%22testy%22%7D') - lib2.register({ test_prop2: 'test_val', distinct_id: 'test2' }) - expect(document.cookie).toEqual('ph__posthog=%7B%22distinct_id%22%3A%22test2%22%7D') - expect(lib2.props).toEqual({ distinct_id: 'test2', test_prop: 'test_value', test_prop2: 'test_val' }) - lib2.remove('ph__posthog') - expect(localStorage.getItem('ph__posthog')).toEqual(null) - expect(document.cookie).toEqual('') - }) + it(`should only call save if props changes`, () => { + let lib = new PostHogPersistence({ name: 'test', persistence: 'localStorage+cookie' }) + lib.register({ distinct_id: 'hi', test_prop: 'test_val' }) + lib.save = jest.fn() - it('should save user state', () => { - let lib = new PostHogPersistence({ name: 'bla', persistence: 'cookie' }) - lib.set_user_state('identified') - expect(document.cookie).toEqual('ph__posthog=%7B%22%24user_state%22%3A%22identified%22%7D') - }) + lib.register({ distinct_id: 'hi', test_prop: 'test_val' }) + lib.register({}) + lib.register({ distinct_id: 'hi' }) + expect(lib.save).toHaveBeenCalledTimes(0) - it('can load user state', () => { - let lib = new PostHogPersistence({ name: 'bla', persistence: 'cookie' }) - lib.set_user_state('identified') - expect(lib.get_user_state()).toEqual('identified') - }) + lib.register({ distinct_id: 'hi2' }) + expect(lib.save).toHaveBeenCalledTimes(1) + lib.save.mockClear() - it('has user state as a reserved property key', () => { - let lib = new PostHogPersistence({ name: 'bla', persistence: 'cookie' }) - lib.register({ distinct_id: 'testy', test_prop: 'test_value' }) - lib.set_user_state('identified') - expect(lib.properties()).toEqual({ distinct_id: 'testy', test_prop: 'test_value' }) - }) + lib.register({ new_key: '1234' }) + expect(lib.save).toHaveBeenCalledTimes(1) + lib.save.mockClear() + }) - it(`should register once LS`, () => { - let lib = new PostHogPersistence({ name: 'test', persistence: 'localStorage+cookie' }) - lib.register_once({ distinct_id: 'hi', test_prop: 'test_val' }) + it('should set direct referrer', () => { + referrer = '' + given.lib.update_referrer_info() - let lib2 = new PostHogPersistence({ name: 'test', persistence: 'localStorage+cookie' }) - expect(lib2.props).toEqual({ distinct_id: 'hi', test_prop: 'test_val' }) - lib.clear() - lib2.clear() - }) + expect(given.lib.props['$referring_domain']).toBe('$direct') + expect(given.lib.props['$referrer']).toBe('$direct') + }) - it(`should only call save if props changes`, () => { - let lib = new PostHogPersistence({ name: 'test', persistence: 'localStorage+cookie' }) - lib.register({ distinct_id: 'hi', test_prop: 'test_val' }) - lib.save = jest.fn() + it('should set external referrer', () => { + referrer = 'https://www.google.com' + given.lib.update_referrer_info() - lib.register({ distinct_id: 'hi', test_prop: 'test_val' }) - lib.register({}) - lib.register({ distinct_id: 'hi' }) - expect(lib.save).toHaveBeenCalledTimes(0) + expect(given.lib.props['$referring_domain']).toBe('www.google.com') + expect(given.lib.props['$referrer']).toBe('https://www.google.com') + }) + + it('should set internal referrer', () => { + referrer = 'https://hedgebox.net/files/abc.png' + given.lib.update_referrer_info() - lib.register({ distinct_id: 'hi2' }) - expect(lib.save).toHaveBeenCalledTimes(1) - lib.save.mockClear() + expect(given.lib.props['$referring_domain']).toBe('hedgebox.net') + expect(given.lib.props['$referrer']).toBe('https://hedgebox.net/files/abc.png') + }) - lib.register({ new_key: '1234' }) - expect(lib.save).toHaveBeenCalledTimes(1) - lib.save.mockClear() + it('extracts enabled feature flags', () => { + given.lib.register({ $enabled_feature_flags: { flag: 'variant', other: true } }) + expect(given.lib.props['$enabled_feature_flags']).toEqual({ flag: 'variant', other: true }) + expect(given.lib.properties()).toEqual({ + '$feature/flag': 'variant', + '$feature/other': true, + }) + }) }) - forPersistenceTypes(function (persistenceType) { - it(`should register once`, () => { - let lib = new PostHogPersistence({ name: 'test', persistence: persistenceType }) - lib.register_once({ distinct_id: 'hi', test_prop: 'test_val' }) + describe('localStorage+cookie', () => { + it('should migrate data from cookies to localStorage', () => { + let lib = new PostHogPersistence({ name: 'bla', persistence: 'cookie' }) + lib.register_once({ distinct_id: 'testy', test_prop: 'test_value' }) + expect(document.cookie).toContain( + 'ph__posthog=%7B%22distinct_id%22%3A%22testy%22%2C%22test_prop%22%3A%22test_value%22%7D' + ) + let lib2 = new PostHogPersistence({ name: 'bla', persistence: 'localStorage+cookie' }) + expect(document.cookie).toContain('ph__posthog=%7B%22distinct_id%22%3A%22testy%22%7D') + lib2.register({ test_prop2: 'test_val', distinct_id: 'test2' }) + expect(document.cookie).toContain('ph__posthog=%7B%22distinct_id%22%3A%22test2%22%7D') + expect(lib2.props).toEqual({ distinct_id: 'test2', test_prop: 'test_value', test_prop2: 'test_val' }) + lib2.remove('ph__posthog') + expect(localStorage.getItem('ph__posthog')).toEqual(null) + expect(document.cookie).toEqual('') + }) - let lib2 = new PostHogPersistence({ name: 'test', persistence: persistenceType }) - expect(lib2.props).toEqual({ distinct_id: 'hi', test_prop: 'test_val' }) - lib.clear() - lib2.clear() + it(`should additionally store certain values in cookies if localStorage+cookie`, () => { + expect(document.cookie).toEqual('') + + const encode = (props) => encodeURIComponent(JSON.stringify(props)) + + let lib = new PostHogPersistence({ name: 'test', persistence: 'localStorage+cookie' }) + lib.register({ distinct_id: 'test', test_prop: 'test_val' }) + expect(document.cookie).toContain( + `ph__posthog=${encode({ + distinct_id: 'test', + })}` + ) + + lib.register({ otherProp: 'prop' }) + expect(document.cookie).toContain( + `ph__posthog=${encode({ + distinct_id: 'test', + })}` + ) + + lib.register({ [SESSION_ID]: [1000, 'sid', 2000] }) + expect(document.cookie).toContain( + `ph__posthog=${encode({ + distinct_id: 'test', + $sesid: [1000, 'sid', 2000], + })}` + ) + + // Clear localstorage to simulate being on a different domain + localStorage.clear() + + const newLib = new PostHogPersistence({ name: 'test', persistence: 'localStorage+cookie' }) + + expect(newLib.props).toEqual({ + distinct_id: 'test', + $sesid: [1000, 'sid', 2000], + }) }) - // Need to add more tests here }) }) diff --git a/src/__tests__/sessionid.js b/src/__tests__/sessionid.js index 17e3e391d..20ce54d6d 100644 --- a/src/__tests__/sessionid.js +++ b/src/__tests__/sessionid.js @@ -1,5 +1,5 @@ import { SessionIdManager } from '../sessionid' -import { SESSION_ID } from '../posthog-persistence' +import { SESSION_ID } from '../constants' import { sessionStore } from '../storage' import { uuidv7 } from '../uuidv7' diff --git a/src/autocapture.ts b/src/autocapture.ts index 2ec2b0935..9b5072162 100644 --- a/src/autocapture.ts +++ b/src/autocapture.ts @@ -27,7 +27,7 @@ import { import RageClick from './extensions/rageclick' import { AutocaptureConfig, AutoCaptureCustomProperty, DecideResponse, Properties } from './types' import { PostHog } from './posthog-core' -import { AUTOCAPTURE_DISABLED_SERVER_SIDE } from './posthog-persistence' +import { AUTOCAPTURE_DISABLED_SERVER_SIDE } from './constants' const autocapture = { _initializedTokens: [] as string[], diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 000000000..620aceb00 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,43 @@ +/* + * Constants + */ + +/* PROPERTY KEYS */ + +// This key is deprecated, but we want to check for it to see whether aliasing is allowed. +export const PEOPLE_DISTINCT_ID_KEY = '$people_distinct_id' +export const DISTINCT_ID = 'distinct_id' +export const ALIAS_ID_KEY = '__alias' +export const CAMPAIGN_IDS_KEY = '__cmpns' +export const EVENT_TIMERS_KEY = '__timers' +export const AUTOCAPTURE_DISABLED_SERVER_SIDE = '$autocapture_disabled_server_side' +export const SESSION_RECORDING_ENABLED_SERVER_SIDE = '$session_recording_enabled_server_side' +export const CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE = '$console_log_recording_enabled_server_side' +export const SESSION_RECORDING_RECORDER_VERSION_SERVER_SIDE = '$session_recording_recorder_version_server_side' // follows rrweb versioning +export const SESSION_ID = '$sesid' +export const ENABLED_FEATURE_FLAGS = '$enabled_feature_flags' +export const PERSISTENCE_EARLY_ACCESS_FEATURES = '$early_access_features' +export const STORED_PERSON_PROPERTIES_KEY = '$stored_person_properties' +export const STORED_GROUP_PROPERTIES_KEY = '$stored_group_properties' +export const SURVEYS = '$surveys' +export const FLAG_CALL_REPORTED = '$flag_call_reported' +export const USER_STATE = '$user_state' +export const POSTHOG_QUOTA_LIMITED = '$posthog_quota_limited' + +// These are propertties that are reserved and will not be automatically included in events +export const PERSISTENCE_RESERVED_PROPERTIES = [ + PEOPLE_DISTINCT_ID_KEY, + ALIAS_ID_KEY, + CAMPAIGN_IDS_KEY, + EVENT_TIMERS_KEY, + SESSION_RECORDING_ENABLED_SERVER_SIDE, + SESSION_ID, + ENABLED_FEATURE_FLAGS, + USER_STATE, + POSTHOG_QUOTA_LIMITED, + PERSISTENCE_EARLY_ACCESS_FEATURES, + STORED_GROUP_PROPERTIES_KEY, + STORED_PERSON_PROPERTIES_KEY, + SURVEYS, + FLAG_CALL_REPORTED, +] diff --git a/src/decide.ts b/src/decide.ts index 67da76ec4..6c9f55cb7 100644 --- a/src/decide.ts +++ b/src/decide.ts @@ -2,7 +2,7 @@ import { autocapture } from './autocapture' import { _base64Encode, loadScript } from './utils' import { PostHog } from './posthog-core' import { Compression, DecideResponse } from './types' -import { STORED_GROUP_PROPERTIES_KEY, STORED_PERSON_PROPERTIES_KEY } from './posthog-persistence' +import { STORED_GROUP_PROPERTIES_KEY, STORED_PERSON_PROPERTIES_KEY } from './constants' export class Decide { instance: PostHog diff --git a/src/extensions/sessionrecording.ts b/src/extensions/sessionrecording.ts index ba7f6cd48..e52de6eff 100644 --- a/src/extensions/sessionrecording.ts +++ b/src/extensions/sessionrecording.ts @@ -2,7 +2,7 @@ import { CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE, SESSION_RECORDING_ENABLED_SERVER_SIDE, SESSION_RECORDING_RECORDER_VERSION_SERVER_SIDE, -} from '../posthog-persistence' +} from '../constants' import { ensureMaxMessageSize, FULL_SNAPSHOT_EVENT_TYPE, diff --git a/src/posthog-core.ts b/src/posthog-core.ts index aeaec96b0..a995c500f 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -18,7 +18,8 @@ import { } from './utils' import { autocapture } from './autocapture' import { PostHogFeatureFlags } from './posthog-featureflags' -import { ALIAS_ID_KEY, FLAG_CALL_REPORTED, PEOPLE_DISTINCT_ID_KEY, PostHogPersistence } from './posthog-persistence' +import { PostHogPersistence } from './posthog-persistence' +import { ALIAS_ID_KEY, FLAG_CALL_REPORTED, PEOPLE_DISTINCT_ID_KEY } from './constants' import { SessionRecording } from './extensions/sessionrecording' import { WebPerformanceObserver } from './extensions/web-performance' import { Decide } from './decide' diff --git a/src/posthog-featureflags.ts b/src/posthog-featureflags.ts index 5a71a5962..5b5b61ae6 100644 --- a/src/posthog-featureflags.ts +++ b/src/posthog-featureflags.ts @@ -9,14 +9,15 @@ import { JsonType, RequestCallback, } from './types' +import { PostHogPersistence } from './posthog-persistence' + import { PERSISTENCE_EARLY_ACCESS_FEATURES, - PostHogPersistence, ENABLED_FEATURE_FLAGS, STORED_GROUP_PROPERTIES_KEY, STORED_PERSON_PROPERTIES_KEY, FLAG_CALL_REPORTED, -} from './posthog-persistence' +} from './constants' const PERSISTENCE_ACTIVE_FEATURE_FLAGS = '$active_feature_flags' const PERSISTENCE_OVERRIDE_FEATURE_FLAGS = '$override_feature_flags' diff --git a/src/posthog-persistence.ts b/src/posthog-persistence.ts index c982c381b..5514e1a03 100644 --- a/src/posthog-persistence.ts +++ b/src/posthog-persistence.ts @@ -3,46 +3,13 @@ import { _each, _extend, _include, _info, _isObject, _isUndefined, _strip_empty_properties, logger } from './utils' import { cookieStore, localStore, localPlusCookieStore, memoryStore, sessionStore } from './storage' import { PersistentStore, PostHogConfig, Properties } from './types' - -/* - * Constants - */ -// This key is deprecated, but we want to check for it to see whether aliasing is allowed. -export const PEOPLE_DISTINCT_ID_KEY = '$people_distinct_id' -export const ALIAS_ID_KEY = '__alias' -export const CAMPAIGN_IDS_KEY = '__cmpns' -export const EVENT_TIMERS_KEY = '__timers' -export const AUTOCAPTURE_DISABLED_SERVER_SIDE = '$autocapture_disabled_server_side' -export const SESSION_RECORDING_ENABLED_SERVER_SIDE = '$session_recording_enabled_server_side' -export const CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE = '$console_log_recording_enabled_server_side' -export const SESSION_RECORDING_RECORDER_VERSION_SERVER_SIDE = '$session_recording_recorder_version_server_side' // follows rrweb versioning -export const SESSION_ID = '$sesid' -export const ENABLED_FEATURE_FLAGS = '$enabled_feature_flags' -export const PERSISTENCE_EARLY_ACCESS_FEATURES = '$early_access_features' -export const STORED_PERSON_PROPERTIES_KEY = '$stored_person_properties' -export const STORED_GROUP_PROPERTIES_KEY = '$stored_group_properties' -export const SURVEYS = '$surveys' -export const FLAG_CALL_REPORTED = '$flag_call_reported' - -const USER_STATE = '$user_state' -const POSTHOG_QUOTA_LIMITED = '$posthog_quota_limited' - -export const RESERVED_PROPERTIES = [ - PEOPLE_DISTINCT_ID_KEY, - ALIAS_ID_KEY, - CAMPAIGN_IDS_KEY, +import { + PERSISTENCE_RESERVED_PROPERTIES, EVENT_TIMERS_KEY, - SESSION_RECORDING_ENABLED_SERVER_SIDE, - SESSION_ID, ENABLED_FEATURE_FLAGS, - USER_STATE, POSTHOG_QUOTA_LIMITED, - PERSISTENCE_EARLY_ACCESS_FEATURES, - STORED_GROUP_PROPERTIES_KEY, - STORED_PERSON_PROPERTIES_KEY, - SURVEYS, - FLAG_CALL_REPORTED, -] + USER_STATE, +} from './constants' const CASE_INSENSITIVE_PERSISTENCE_TYPES: readonly Lowercase[] = [ 'cookie', @@ -126,7 +93,7 @@ export class PostHogPersistence { for (let i = 0; i < keys.length; i++) { p[`$feature/${keys[i]}`] = v[keys[i]] } - } else if (!_include(RESERVED_PROPERTIES, k)) { + } else if (!_include(PERSISTENCE_RESERVED_PROPERTIES, k)) { p[k] = v } }) diff --git a/src/posthog-surveys.ts b/src/posthog-surveys.ts index 7d98b5875..c94bbbb3b 100644 --- a/src/posthog-surveys.ts +++ b/src/posthog-surveys.ts @@ -1,5 +1,5 @@ import { PostHog } from './posthog-core' -import { SURVEYS } from './posthog-persistence' +import { SURVEYS } from './constants' /** * Having Survey types in types.ts was confusing tsc diff --git a/src/sessionid.ts b/src/sessionid.ts index a18598b09..93bcb12b6 100644 --- a/src/sessionid.ts +++ b/src/sessionid.ts @@ -1,4 +1,5 @@ -import { PostHogPersistence, SESSION_ID } from './posthog-persistence' +import { PostHogPersistence } from './posthog-persistence' +import { SESSION_ID } from './constants' import { sessionStore } from './storage' import { PostHogConfig, SessionIdChangedCallback } from './types' import { uuidv7 } from './uuidv7' diff --git a/src/storage.ts b/src/storage.ts index 0334c95d0..97b1cb2d9 100644 --- a/src/storage.ts +++ b/src/storage.ts @@ -1,6 +1,7 @@ import { _extend, logger } from './utils' import { PersistentStore, Properties } from './types' import Config from './config' +import { DISTINCT_ID, SESSION_ID } from './constants' const DOMAIN_MATCH_REGEX = /[a-z0-9][a-z0-9-]+\.[a-z.]{2,6}$/i @@ -15,7 +16,7 @@ export const cookieStore: PersistentStore = { get: function (name) { try { const nameEQ = name + '=' - const ca = document.cookie.split(';') + const ca = document.cookie.split(';').filter((x) => x.length) for (let i = 0; i < ca.length; i++) { let c = ca[i] while (c.charAt(0) == ' ') { @@ -46,6 +47,7 @@ export const cookieStore: PersistentStore = { secure = '' if (cross_subdomain) { + // NOTE: Could we use this for cross domain tracking? const matches = document.location.hostname.match(DOMAIN_MATCH_REGEX), domain = matches ? matches[0] : '' @@ -157,9 +159,11 @@ export const localStore: PersistentStore = { }, } -// Use localstorage for most data but still use cookie for distinct_id +// Use localstorage for most data but still use cookie for COOKIE_PERSISTED_PROPERTIES // This solves issues with cookies having too much data in them causing headers too large // Also makes sure we don't have to send a ton of data to the server +const COOKIE_PERSISTED_PROPERTIES = [DISTINCT_ID, SESSION_ID] + export const localPlusCookieStore: PersistentStore = { ...localStore, parse: function (name) { @@ -168,9 +172,6 @@ export const localPlusCookieStore: PersistentStore = { try { // See if there's a cookie stored with data. extend = cookieStore.parse(name) || {} - if (extend['distinct_id']) { - cookieStore.set(name, { distinct_id: extend['distinct_id'] }) - } } catch (err) {} const value = _extend(extend, JSON.parse(localStore.get(name) || '{}')) localStore.set(name, value) @@ -184,8 +185,15 @@ export const localPlusCookieStore: PersistentStore = { set: function (name, value, days, cross_subdomain, is_secure) { try { localStore.set(name, value) - if (value.distinct_id) { - cookieStore.set(name, { distinct_id: value.distinct_id }, days, cross_subdomain, is_secure) + const cookiePersistedProperties: Record = {} + COOKIE_PERSISTED_PROPERTIES.forEach((key) => { + if (value[key]) { + cookiePersistedProperties[key] = value[key] + } + }) + + if (Object.keys(cookiePersistedProperties).length) { + cookieStore.set(name, cookiePersistedProperties, days, cross_subdomain, is_secure) } } catch (err) { localStore.error(err)