From 6316a846d8927fc2f0c60f4eb72fec641284522a Mon Sep 17 00:00:00 2001 From: Ben White Date: Tue, 7 May 2024 16:33:48 +0200 Subject: [PATCH 1/5] Refactor request to make sure we only use available transports --- src/posthog-core.ts | 1 - src/request.ts | 84 +++++++++++++++++++++++++++++---------------- 2 files changed, 54 insertions(+), 31 deletions(-) diff --git a/src/posthog-core.ts b/src/posthog-core.ts index 2a6d717a8..a6dc05dff 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -116,7 +116,6 @@ let ENQUEUE_REQUESTS = !SUPPORTS_REQUEST && userAgent?.indexOf('MSIE') === -1 && export const defaultConfig = (): PostHogConfig => ({ api_host: 'https://us.i.posthog.com', - api_transport: 'XHR', ui_host: null, token: '', autocapture: true, diff --git a/src/request.ts b/src/request.ts index 55eba7a0e..57403c661 100644 --- a/src/request.ts +++ b/src/request.ts @@ -19,36 +19,6 @@ type EncodedBody = { body: string | BlobPart } -// This is the entrypoint. It takes care of sanitizing the options and then calls the appropriate request method. -export const request = (_options: RequestOptions) => { - // Clone the options so we don't modify the original object - const options = { ..._options } - options.timeout = options.timeout || 60000 - - options.url = extendURLParams(options.url, { - _: new Date().getTime().toString(), - ver: Config.LIB_VERSION, - compression: options.compression, - }) - - if (options.transport === 'sendBeacon' && navigator?.sendBeacon) { - return _sendBeacon(options) - } - - // NOTE: Until we are confident with it, we only use fetch if explicitly told so - // At some point we will make it the default over xhr - if (options.transport === 'fetch' && fetch) { - return _fetch(options) - } - - if (XMLHttpRequest || !document) { - return xhr(options) - } - - // Final fallback if everything else fails... - scriptRequest(options) -} - export const extendURLParams = (url: string, params: Record): string => { const [baseUrl, search] = url.split('?') const newParams = { ...params } @@ -225,3 +195,57 @@ const scriptRequest = (options: RequestOptions) => { const s = document.getElementsByTagName('script')[0] s.parentNode?.insertBefore(script, s) } + +const AVAILABLE_TRANSPORTS: { transport: RequestOptions['transport']; method: (options: RequestOptions) => void }[] = [] + +// We add the transports in order of preference + +if (XMLHttpRequest) { + AVAILABLE_TRANSPORTS.push({ + transport: 'XHR', + method: xhr, + }) +} + +if (fetch) { + AVAILABLE_TRANSPORTS.push({ + transport: 'fetch', + method: _fetch, + }) +} + +if (navigator?.sendBeacon) { + AVAILABLE_TRANSPORTS.push({ + transport: 'sendBeacon', + method: _sendBeacon, + }) +} + +AVAILABLE_TRANSPORTS.push({ + transport: undefined, + method: scriptRequest, +}) + +// This is the entrypoint. It takes care of sanitizing the options and then calls the appropriate request method. +export const request = (_options: RequestOptions) => { + // Clone the options so we don't modify the original object + const options = { ..._options } + options.timeout = options.timeout || 60000 + + options.url = extendURLParams(options.url, { + _: new Date().getTime().toString(), + ver: Config.LIB_VERSION, + compression: options.compression, + }) + + const transport = options.transport ?? 'XHR' + + const transportMethod = + AVAILABLE_TRANSPORTS.find((t) => t.transport === transport)?.method ?? AVAILABLE_TRANSPORTS[0].method + + if (!transportMethod) { + throw new Error('No available transport method') + } + + transportMethod(options) +} From 22dbebf5b2ed8fb2e1604a98038edfebd720b8ef Mon Sep 17 00:00:00 2001 From: Ben White Date: Tue, 7 May 2024 16:42:39 +0200 Subject: [PATCH 2/5] Fix for ie11 --- src/request.ts | 4 ++-- src/utils/index.ts | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/request.ts b/src/request.ts index 57403c661..d525815f8 100644 --- a/src/request.ts +++ b/src/request.ts @@ -1,4 +1,4 @@ -import { _base64Encode, each } from './utils' +import { _base64Encode, each, find } from './utils' import Config from './config' import { Compression, RequestOptions, RequestResponse } from './types' import { formDataToQuery } from './utils/request-utils' @@ -241,7 +241,7 @@ export const request = (_options: RequestOptions) => { const transport = options.transport ?? 'XHR' const transportMethod = - AVAILABLE_TRANSPORTS.find((t) => t.transport === transport)?.method ?? AVAILABLE_TRANSPORTS[0].method + find(AVAILABLE_TRANSPORTS, (t) => t.transport === transport)?.method ?? AVAILABLE_TRANSPORTS[0].method if (!transportMethod) { throw new Error('No available transport method') diff --git a/src/utils/index.ts b/src/utils/index.ts index 1bb1838eb..78ba94fc2 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -444,3 +444,12 @@ export function isCrossDomainCookie(documentLocation: Location | undefined) { export function isDistinctIdStringLike(value: string): boolean { return ['distinct_id', 'distinctid'].includes(value.toLowerCase()) } + +export function find(value: T[], predicate: (value: T) => boolean): T | undefined { + for (let i = 0; i < value.length; i++) { + if (predicate(value[i])) { + return value[i] + } + } + return undefined +} From a57feffd62eb4efb2c177936eda1889a3adc6405 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Tue, 7 May 2024 17:44:10 +0100 Subject: [PATCH 3/5] unforgivable cheeky merge and fix --- src/extensions/toolbar.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extensions/toolbar.ts b/src/extensions/toolbar.ts index ed2a2f872..3bb1dd3b4 100644 --- a/src/extensions/toolbar.ts +++ b/src/extensions/toolbar.ts @@ -82,7 +82,7 @@ export class Toolbar { location.hash = state['desiredHash'] } else if (history) { // second param is unused see https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState - history.replaceState(history.state, "", location.pathname + location.search) // completely remove hash + history.replaceState(history.state, '', location.pathname + location.search) // completely remove hash } else { location.hash = '' // clear hash (but leaves # unfortunately) } From 2da356c5f95da735d3d48f18e67c7513a8305b6d Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Tue, 7 May 2024 18:21:11 +0100 Subject: [PATCH 4/5] fix: remove trying to send events to posthog by adding a script tag --- src/request.ts | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/request.ts b/src/request.ts index d525815f8..60d691900 100644 --- a/src/request.ts +++ b/src/request.ts @@ -4,7 +4,7 @@ import { Compression, RequestOptions, RequestResponse } from './types' import { formDataToQuery } from './utils/request-utils' import { logger } from './utils/logger' -import { fetch, document, XMLHttpRequest, AbortController, navigator } from './utils/globals' +import { fetch, XMLHttpRequest, AbortController, navigator } from './utils/globals' import { gzipSync, strToU8 } from 'fflate' // eslint-disable-next-line compat/compat @@ -183,19 +183,6 @@ const _sendBeacon = (options: RequestOptions) => { } } -const scriptRequest = (options: RequestOptions) => { - if (!document) { - return - } - const script = document.createElement('script') - script.type = 'text/javascript' - script.async = true - script.defer = true - script.src = options.url - const s = document.getElementsByTagName('script')[0] - s.parentNode?.insertBefore(script, s) -} - const AVAILABLE_TRANSPORTS: { transport: RequestOptions['transport']; method: (options: RequestOptions) => void }[] = [] // We add the transports in order of preference @@ -221,11 +208,6 @@ if (navigator?.sendBeacon) { }) } -AVAILABLE_TRANSPORTS.push({ - transport: undefined, - method: scriptRequest, -}) - // This is the entrypoint. It takes care of sanitizing the options and then calls the appropriate request method. export const request = (_options: RequestOptions) => { // Clone the options so we don't modify the original object From 450c11419c23f99a8db102863b25fef855875781 Mon Sep 17 00:00:00 2001 From: Ben White Date: Wed, 8 May 2024 09:17:43 +0200 Subject: [PATCH 5/5] Fix? --- src/request.ts | 54 -------------------------------------------------- 1 file changed, 54 deletions(-) diff --git a/src/request.ts b/src/request.ts index f6ca5d232..60d691900 100644 --- a/src/request.ts +++ b/src/request.ts @@ -231,57 +231,3 @@ export const request = (_options: RequestOptions) => { transportMethod(options) } - -const AVAILABLE_TRANSPORTS: { transport: RequestOptions['transport']; method: (options: RequestOptions) => void }[] = [] - -// We add the transports in order of preference - -if (XMLHttpRequest) { - AVAILABLE_TRANSPORTS.push({ - transport: 'XHR', - method: xhr, - }) -} - -if (fetch) { - AVAILABLE_TRANSPORTS.push({ - transport: 'fetch', - method: _fetch, - }) -} - -if (navigator?.sendBeacon) { - AVAILABLE_TRANSPORTS.push({ - transport: 'sendBeacon', - method: _sendBeacon, - }) -} - -AVAILABLE_TRANSPORTS.push({ - transport: undefined, - method: scriptRequest, -}) - -// This is the entrypoint. It takes care of sanitizing the options and then calls the appropriate request method. -export const request = (_options: RequestOptions) => { - // Clone the options so we don't modify the original object - const options = { ..._options } - options.timeout = options.timeout || 60000 - - options.url = extendURLParams(options.url, { - _: new Date().getTime().toString(), - ver: Config.LIB_VERSION, - compression: options.compression, - }) - - const transport = options.transport ?? 'XHR' - - const transportMethod = - find(AVAILABLE_TRANSPORTS, (t) => t.transport === transport)?.method ?? AVAILABLE_TRANSPORTS[0].method - - if (!transportMethod) { - throw new Error('No available transport method') - } - - transportMethod(options) -}