From 2f1dac8cffb66880f50658599a804c2e218a43d6 Mon Sep 17 00:00:00 2001 From: Seth Silesky <5115498+silesky@users.noreply.github.com> Date: Wed, 17 Jul 2024 17:11:19 -0500 Subject: [PATCH 1/4] add network signals so they always include a full URL --- .../__tests__/normalize-url.test.ts | 52 +++++++++++++++++++ .../src/core/signal-generators/network-gen.ts | 3 +- .../core/signal-generators/normalize-url.ts | 15 ++++++ .../signals/src/test-helpers/set-location.ts | 9 ++++ 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 packages/signals/signals/src/core/signal-generators/__tests__/normalize-url.test.ts create mode 100644 packages/signals/signals/src/core/signal-generators/normalize-url.ts create mode 100644 packages/signals/signals/src/test-helpers/set-location.ts diff --git a/packages/signals/signals/src/core/signal-generators/__tests__/normalize-url.test.ts b/packages/signals/signals/src/core/signal-generators/__tests__/normalize-url.test.ts new file mode 100644 index 000000000..6c06f38da --- /dev/null +++ b/packages/signals/signals/src/core/signal-generators/__tests__/normalize-url.test.ts @@ -0,0 +1,52 @@ +import { setLocation } from '../../../test-helpers/set-location' +import { normalizeUrl } from '../normalize-url' + +describe('normalizeUrl', () => { + beforeEach(() => { + setLocation({ hostname: 'www.currentsite.com' }) + setLocation({ protocol: 'https:' }) + }) + + it('should return the same URL if it starts with http', () => { + const url = 'https://www.example.com' + expect(normalizeUrl(url)).toBe('https://www.example.com') + }) + + it('should work with subdomains', () => { + const url = 'https://api.example.com' + expect(normalizeUrl(url)).toBe('https://api.example.com') + }) + + it('should prepend hostname to path starting with /', () => { + const url = '/foo/bar' + expect(normalizeUrl(url)).toBe('www.currentsite.com/foo/bar') + }) + + it('should prepend hostname and / to path not starting with /', () => { + const url = 'foo/bar' + expect(normalizeUrl(url)).toBe('www.currentsite.com/foo/bar') + }) + + it('should prepend hostname and / to a single word path', () => { + const url = 'foo' + expect(normalizeUrl(url)).toBe('www.currentsite.com/foo') + }) + + it('should use the current protocol of the page if none is provided', () => { + const url = 'example.com/bar' + setLocation({ protocol: 'http:' }) + expect(normalizeUrl(url)).toBe('http://example.com/bar') + }) + + it('should work if no /', () => { + const url = 'example.com' + setLocation({ protocol: 'http:' }) + expect(normalizeUrl(url)).toBe('http://example.com') + }) + + it('protocols should work with subdomains', () => { + const url = 'api.example.com/foo' + setLocation({ protocol: 'http:' }) + expect(normalizeUrl(url)).toBe('http://api.example.com/foo') + }) +}) diff --git a/packages/signals/signals/src/core/signal-generators/network-gen.ts b/packages/signals/signals/src/core/signal-generators/network-gen.ts index ee7043bb4..b4c293820 100644 --- a/packages/signals/signals/src/core/signal-generators/network-gen.ts +++ b/packages/signals/signals/src/core/signal-generators/network-gen.ts @@ -1,6 +1,7 @@ import { logger } from '../../lib/logger' import { createNetworkSignal } from '../../types' import { SignalEmitter } from '../emitter' +import { normalizeUrl } from './normalize-url' import { SignalGenerator } from './types' let origFetch: typeof window.fetch @@ -68,7 +69,7 @@ export class NetworkGenerator implements SignalGenerator { emitter.emit( createNetworkSignal({ action: 'Request', - url: sUrl, + url: normalizeUrl(sUrl), method: rq.method || '', data: JSON.parse(rq.body.toString()), }) diff --git a/packages/signals/signals/src/core/signal-generators/normalize-url.ts b/packages/signals/signals/src/core/signal-generators/normalize-url.ts new file mode 100644 index 000000000..7d9e2869d --- /dev/null +++ b/packages/signals/signals/src/core/signal-generators/normalize-url.ts @@ -0,0 +1,15 @@ +/** + * Normalize URL provided by the fetch API into a valid URL string that can be used with new URL. + */ +export const normalizeUrl = (urlOrPath: string): string => { + if (urlOrPath.startsWith('http')) { + return urlOrPath + } + if (urlOrPath.startsWith('/')) { + return window.location.hostname + urlOrPath + } + if (urlOrPath.includes('.')) { + return `${location.protocol}//${urlOrPath}` + } + return window.location.hostname + '/' + urlOrPath +} diff --git a/packages/signals/signals/src/test-helpers/set-location.ts b/packages/signals/signals/src/test-helpers/set-location.ts new file mode 100644 index 000000000..142805e57 --- /dev/null +++ b/packages/signals/signals/src/test-helpers/set-location.ts @@ -0,0 +1,9 @@ +export const setLocation = (location: Partial = {}) => { + Object.defineProperty(window, 'location', { + value: { + ...window.location, + ...location, + }, + writable: true, + }) +} From 03064eb1d6efba976273d193fde53f7eb9c7d6ee Mon Sep 17 00:00:00 2001 From: Seth Silesky <5115498+silesky@users.noreply.github.com> Date: Wed, 17 Jul 2024 17:11:55 -0500 Subject: [PATCH 2/4] add network signals to include a full url --- .changeset/chatty-flowers-roll.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/chatty-flowers-roll.md diff --git a/.changeset/chatty-flowers-roll.md b/.changeset/chatty-flowers-roll.md new file mode 100644 index 000000000..4df0ea168 --- /dev/null +++ b/.changeset/chatty-flowers-roll.md @@ -0,0 +1,5 @@ +--- +'@segment/analytics-signals': patch +--- + +Update network signals to include a full url From a05e20c88386c2b6284e75f85ea5f922d50ea987 Mon Sep 17 00:00:00 2001 From: Seth Silesky <5115498+silesky@users.noreply.github.com> Date: Wed, 17 Jul 2024 17:18:49 -0500 Subject: [PATCH 3/4] wip --- .../signal-generators/__tests__/network.test.ts | 15 +++------------ .../__tests__/normalize-url.test.ts | 3 +-- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/packages/signals/signals/src/core/signal-generators/__tests__/network.test.ts b/packages/signals/signals/src/core/signal-generators/__tests__/network.test.ts index 43b61d153..309f5bf48 100644 --- a/packages/signals/signals/src/core/signal-generators/__tests__/network.test.ts +++ b/packages/signals/signals/src/core/signal-generators/__tests__/network.test.ts @@ -7,6 +7,7 @@ import { import { SignalEmitter } from '../../emitter' import { Response } from 'node-fetch' import { sleep } from '@segment/analytics-core' +import { setLocation } from '../../../test-helpers/set-location' describe(containsJSONContent, () => { it('should return true if headers contain application/json', () => { @@ -31,18 +32,8 @@ describe(containsJSONContent, () => { }) describe(matchHostname, () => { - const setHostname = (hostname: string) => { - Object.defineProperty(window, 'location', { - value: { - ...window.location, - hostname: hostname, - }, - writable: true, - }) - } - beforeEach(() => { - setHostname('example.com') + setLocation({ hostname: 'example.com' }) }) it('should only match first party domains', () => { expect(matchHostname('https://www.example.com')).toBe(true) @@ -54,7 +45,7 @@ describe(matchHostname, () => { }) it('should work with subdomains', () => { - setHostname('api.example.com') + setLocation({ hostname: 'api.example.com' }) expect(matchHostname('https://api.example.com/foo')).toBe(true) expect(matchHostname('https://foo.com/foo')).toBe(false) expect(matchHostname('https://example.com/foo')).toBe(false) diff --git a/packages/signals/signals/src/core/signal-generators/__tests__/normalize-url.test.ts b/packages/signals/signals/src/core/signal-generators/__tests__/normalize-url.test.ts index 6c06f38da..194dbe77e 100644 --- a/packages/signals/signals/src/core/signal-generators/__tests__/normalize-url.test.ts +++ b/packages/signals/signals/src/core/signal-generators/__tests__/normalize-url.test.ts @@ -3,8 +3,7 @@ import { normalizeUrl } from '../normalize-url' describe('normalizeUrl', () => { beforeEach(() => { - setLocation({ hostname: 'www.currentsite.com' }) - setLocation({ protocol: 'https:' }) + setLocation({ hostname: 'www.currentsite.com', protocol: 'https:' }) }) it('should return the same URL if it starts with http', () => { From b6766ae41b62a971d06c2339bd6f78072462dea4 Mon Sep 17 00:00:00 2001 From: Seth Silesky <5115498+silesky@users.noreply.github.com> Date: Thu, 18 Jul 2024 11:47:01 -0500 Subject: [PATCH 4/4] update URL --- .../signal-generators/__tests__/normalize-url.test.ts | 8 ++++---- .../signals/src/core/signal-generators/normalize-url.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/signals/signals/src/core/signal-generators/__tests__/normalize-url.test.ts b/packages/signals/signals/src/core/signal-generators/__tests__/normalize-url.test.ts index 194dbe77e..169f38d7c 100644 --- a/packages/signals/signals/src/core/signal-generators/__tests__/normalize-url.test.ts +++ b/packages/signals/signals/src/core/signal-generators/__tests__/normalize-url.test.ts @@ -3,7 +3,7 @@ import { normalizeUrl } from '../normalize-url' describe('normalizeUrl', () => { beforeEach(() => { - setLocation({ hostname: 'www.currentsite.com', protocol: 'https:' }) + setLocation({ origin: 'https://www.currentsite.com', protocol: 'https:' }) }) it('should return the same URL if it starts with http', () => { @@ -18,17 +18,17 @@ describe('normalizeUrl', () => { it('should prepend hostname to path starting with /', () => { const url = '/foo/bar' - expect(normalizeUrl(url)).toBe('www.currentsite.com/foo/bar') + expect(normalizeUrl(url)).toBe('https://www.currentsite.com/foo/bar') }) it('should prepend hostname and / to path not starting with /', () => { const url = 'foo/bar' - expect(normalizeUrl(url)).toBe('www.currentsite.com/foo/bar') + expect(normalizeUrl(url)).toBe('https://www.currentsite.com/foo/bar') }) it('should prepend hostname and / to a single word path', () => { const url = 'foo' - expect(normalizeUrl(url)).toBe('www.currentsite.com/foo') + expect(normalizeUrl(url)).toBe('https://www.currentsite.com/foo') }) it('should use the current protocol of the page if none is provided', () => { diff --git a/packages/signals/signals/src/core/signal-generators/normalize-url.ts b/packages/signals/signals/src/core/signal-generators/normalize-url.ts index 7d9e2869d..72f8dad0d 100644 --- a/packages/signals/signals/src/core/signal-generators/normalize-url.ts +++ b/packages/signals/signals/src/core/signal-generators/normalize-url.ts @@ -6,10 +6,10 @@ export const normalizeUrl = (urlOrPath: string): string => { return urlOrPath } if (urlOrPath.startsWith('/')) { - return window.location.hostname + urlOrPath + return window.location.origin + urlOrPath } if (urlOrPath.includes('.')) { return `${location.protocol}//${urlOrPath}` } - return window.location.hostname + '/' + urlOrPath + return window.location.origin + '/' + urlOrPath }