diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e53d1d38..6cea8b69f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## 1.194.2 - 2024-12-02 + +- fix: use previous site-app variables (#1574) + +## 1.194.1 - 2024-11-30 + +- fix: Don't crash on bigints (#1573) +- feat: Add customization to print events drop them (#1572) + +## 1.194.0 - 2024-11-29 + +- feat: add $recording_status property (#1571) + ## 1.193.1 - 2024-11-28 - fix: zone detection (#1570) diff --git a/package.json b/package.json index 7f864ef43..0fde770ed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "posthog-js", - "version": "1.193.1", + "version": "1.194.2", "description": "Posthog-js allows you to automatically capture usage and send events to PostHog.", "repository": "https://github.com/PostHog/posthog-js", "author": "hey@posthog.com", diff --git a/src/__tests__/request.test.ts b/src/__tests__/request.test.ts index f5ecd72d2..6456321d0 100644 --- a/src/__tests__/request.test.ts +++ b/src/__tests__/request.test.ts @@ -343,6 +343,21 @@ describe('request', () => { 'application/x-www-form-urlencoded' ) }) + + it('converts bigint properties to string without throwing', () => { + request( + createRequest({ + url: 'https://any.posthog-instance.com/', + method: 'POST', + compression: Compression.Base64, + data: { foo: BigInt('999999999999999999999') }, + }) + ) + expect(mockedXHR.send.mock.calls[0][0]).toMatchInlineSnapshot( + `"data=eyJmb28iOiI5OTk5OTk5OTk5OTk5OTk5OTk5OTkifQ%3D%3D"` + ) + expect(mockedXHR.setRequestHeader).toHaveBeenCalledWith('Content-Type', 'application/x-www-form-urlencoded') + }) }) describe('sendBeacon', () => { diff --git a/src/__tests__/site-apps.ts b/src/__tests__/site-apps.ts index 6c670eeb4..7964a7e17 100644 --- a/src/__tests__/site-apps.ts +++ b/src/__tests__/site-apps.ts @@ -295,7 +295,7 @@ describe('SiteApps', () => { siteAppsInstance.afterDecideResponse(response) - expect(assignableWindow['__$$ph_site_app_1_posthog']).toBe(posthog) + expect(assignableWindow['__$$ph_site_app_1']).toBe(posthog) expect(typeof assignableWindow['__$$ph_site_app_1_missed_invocations']).toBe('function') expect(typeof assignableWindow['__$$ph_site_app_1_callback']).toBe('function') expect(assignableWindow.__PosthogExtensions__?.loadSiteApp).toHaveBeenCalledWith( diff --git a/src/customizations/before-send.ts b/src/customizations/before-send.ts index 0f28c4d4a..dc72de278 100644 --- a/src/customizations/before-send.ts +++ b/src/customizations/before-send.ts @@ -117,3 +117,9 @@ export function sampleByEvent(eventNames: KnownEventName[], percent: number): Be : null } } + +export const printAndDropEverything: BeforeSendFn = (result) => { + // eslint-disable-next-line no-console + console.log('Would have sent event:', result) + return null +} diff --git a/src/request.ts b/src/request.ts index 0bef5bb6e..3d5a46bb7 100644 --- a/src/request.ts +++ b/src/request.ts @@ -41,8 +41,17 @@ export const extendURLParams = (url: string, params: Record): strin return `${baseUrl}?${newSearch}` } +export const jsonStringify = (data: any, space?: string | number): string => { + // With plain JSON.stringify, we get an exception when a property is a BigInt. This has caused problems for some users, + // see https://github.com/PostHog/posthog-js/issues/1440 + // To work around this, we convert BigInts to strings before stringifying the data. This is not ideal, as we lose + // information that this was originally a number, but given ClickHouse doesn't support BigInts, the customer + // would not be able to operate on these numerically anyway. + return JSON.stringify(data, (_, value) => (typeof value === 'bigint' ? value.toString() : value), space) +} + const encodeToDataString = (data: string | Record): string => { - return 'data=' + encodeURIComponent(typeof data === 'string' ? data : JSON.stringify(data)) + return 'data=' + encodeURIComponent(typeof data === 'string' ? data : jsonStringify(data)) } const encodePostData = ({ data, compression }: RequestOptions): EncodedBody | undefined => { @@ -51,7 +60,7 @@ const encodePostData = ({ data, compression }: RequestOptions): EncodedBody | un } if (compression === Compression.GZipJS) { - const gzipData = gzipSync(strToU8(JSON.stringify(data)), { mtime: 0 }) + const gzipData = gzipSync(strToU8(jsonStringify(data)), { mtime: 0 }) const blob = new Blob([gzipData], { type: CONTENT_TYPE_PLAIN }) return { contentType: CONTENT_TYPE_PLAIN, @@ -61,7 +70,7 @@ const encodePostData = ({ data, compression }: RequestOptions): EncodedBody | un } if (compression === Compression.Base64) { - const b64data = _base64Encode(JSON.stringify(data)) + const b64data = _base64Encode(jsonStringify(data)) const encodedBody = encodeToDataString(b64data) return { @@ -71,7 +80,7 @@ const encodePostData = ({ data, compression }: RequestOptions): EncodedBody | un } } - const jsonBody = JSON.stringify(data) + const jsonBody = jsonStringify(data) return { contentType: CONTENT_TYPE_JSON, body: jsonBody, diff --git a/src/site-apps.ts b/src/site-apps.ts index 73414ace1..9bb507e34 100644 --- a/src/site-apps.ts +++ b/src/site-apps.ts @@ -87,7 +87,7 @@ export class SiteApps { for (const { id, url } of response['siteApps']) { // TODO: if we have opted out and "type" is "site_destination", ignore it... but do include "site_app" types this.appsLoading.add(id) - assignableWindow[`__$$ph_site_app_${id}_posthog`] = this.instance + assignableWindow[`__$$ph_site_app_${id}`] = this.instance assignableWindow[`__$$ph_site_app_${id}_missed_invocations`] = () => this.missedInvocations assignableWindow[`__$$ph_site_app_${id}_callback`] = () => { this.appsLoading.delete(id)