From 46627dae6e6ec3fe3fb48035b40bf8eafa421b53 Mon Sep 17 00:00:00 2001 From: Ben White Date: Tue, 24 Oct 2023 14:34:33 +0200 Subject: [PATCH 1/2] Added quicker loading of state and parsing of base64 encoded content --- src/extensions/toolbar.ts | 27 +++++++++++++++++++++++---- src/utils.ts | 8 ++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/extensions/toolbar.ts b/src/extensions/toolbar.ts index f4e2af8ee..d1d1fbfe1 100644 --- a/src/extensions/toolbar.ts +++ b/src/extensions/toolbar.ts @@ -1,8 +1,14 @@ -import { _getHashParam, _register_event, loadScript, logger } from '../utils' +import { _getHashParam, _register_event, _try, loadScript, logger, window } from '../utils' import { PostHog } from '../posthog-core' import { DecideResponse, ToolbarParams } from '../types' import { POSTHOG_MANAGED_HOSTS } from './cloud' +// TRICKY: Many web frameworks will modify the route on load, potentially before posthog is initialized. +// To get ahead of this we grab it as soon as the posthog-js is parsed +const STATE_FROM_WINDOW = window.location + ? _getHashParam(window.location.hash, '__posthog') || _getHashParam(location.hash, 'state') + : null + export class Toolbar { instance: PostHog constructor(instance: PostHog) { @@ -49,10 +55,23 @@ export class Toolbar { localStorage = window.localStorage } - const stateHash = _getHashParam(location.hash, '__posthog') || _getHashParam(location.hash, 'state') - const state = stateHash ? JSON.parse(decodeURIComponent(stateHash)) : null - const parseFromUrl = state && state['action'] === 'ph_authorize' + /** + * Info about the state + * The state is a json object + * 1. (Legacy) The state can be `state={}` as a urlencoded object of info. In this case + * 2. The state should now be found in `__posthog={}` and can be base64 encoded or urlencoded. + * 3. Base64 encoding is preferred and will gradually be rolled out everywhere + */ + + const stateHash = + STATE_FROM_WINDOW || _getHashParam(location.hash, '__posthog') || _getHashParam(location.hash, 'state') + let toolbarParams: ToolbarParams + const state = stateHash + ? _try(() => JSON.parse(atob(stateHash))) || _try(() => JSON.parse(decodeURIComponent(stateHash))) + : null + + const parseFromUrl = state && state['action'] === 'ph_authorize' if (parseFromUrl) { // happens if they are initializing the toolbar using an old snippet diff --git a/src/utils.ts b/src/utils.ts index 7d765f124..b2bc56b76 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -274,6 +274,14 @@ export const _formatDate = function (d: Date): string { ) } +export const _try = function (fn: () => T): T | undefined { + try { + return fn() + } catch (e) { + return undefined + } +} + export const _safewrap = function any = (...args: any[]) => any>(f: F): F { return function (...args) { try { From ebbcb4fafeb31218065f376366bd93c3bf4ad75c Mon Sep 17 00:00:00 2001 From: Ben White Date: Tue, 24 Oct 2023 14:34:53 +0200 Subject: [PATCH 2/2] Fixes --- src/extensions/toolbar.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/extensions/toolbar.ts b/src/extensions/toolbar.ts index d1d1fbfe1..e7d41ec47 100644 --- a/src/extensions/toolbar.ts +++ b/src/extensions/toolbar.ts @@ -68,7 +68,8 @@ export class Toolbar { let toolbarParams: ToolbarParams const state = stateHash - ? _try(() => JSON.parse(atob(stateHash))) || _try(() => JSON.parse(decodeURIComponent(stateHash))) + ? _try(() => JSON.parse(atob(decodeURIComponent(stateHash)))) || + _try(() => JSON.parse(decodeURIComponent(stateHash))) : null const parseFromUrl = state && state['action'] === 'ph_authorize'