From 11178e33214f0df2229e41e897c1b091b81dced2 Mon Sep 17 00:00:00 2001 From: feugy Date: Fri, 6 Feb 2026 18:50:53 +0100 Subject: [PATCH] fix: src and endpoint paths do not work when relative --- .gitignore | 1 + packages/web/src/utils.test.ts | 17 +++++++++++++++++ packages/web/src/utils.ts | 20 ++++++++++++++------ packages/web/src/vue/create-component.ts | 5 ++++- 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 21efa56..37cbef1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ dist .vscode .vercel .claude +.env*.local diff --git a/packages/web/src/utils.test.ts b/packages/web/src/utils.test.ts index 6f097b1..9ef8ea2 100644 --- a/packages/web/src/utils.test.ts +++ b/packages/web/src/utils.test.ts @@ -271,6 +271,13 @@ describe('utils', () => { ).toBe(scriptSrc); }); + it('adds leading slash to config value', () => { + const scriptSrc = `${Math.random()}.js`; + expect( + loadProps({}, JSON.stringify({ analytics: { scriptSrc } })).src, + ).toBe(`/${scriptSrc}`); + }); + it('uses props over config string', () => { const scriptSrc = `https://example.com/${Math.random()}.js`; expect( @@ -280,6 +287,16 @@ describe('utils', () => { ).src, ).toBe(scriptSrc); }); + + it('adds leading slash to props value', () => { + const scriptSrc = `${Math.random()}.js`; + expect( + loadProps( + { scriptSrc }, + JSON.stringify({ analytics: { scriptSrc: 'notused' } }), + ).src, + ).toBe(`/${scriptSrc}`); + }); }); describe('dataset', () => { diff --git a/packages/web/src/utils.ts b/packages/web/src/utils.ts index ad68c8b..bcd89f6 100644 --- a/packages/web/src/utils.ts +++ b/packages/web/src/utils.ts @@ -126,13 +126,13 @@ function escapeRegExp(string: string): string { function getScriptSrc(props: AnalyticsProps & { basePath?: string }): string { if (props.scriptSrc) { - return props.scriptSrc; + return makeAbsolute(props.scriptSrc); } if (isDevelopment()) { return 'https://va.vercel-scripts.com/v1/script.debug.js'; } if (props.basePath) { - return `${props.basePath}/insights/script.js`; + return makeAbsolute(`${props.basePath}/insights/script.js`); } return '/_vercel/insights/script.js'; } @@ -166,13 +166,13 @@ export function loadProps( dataset.disableAutoTrack = '1'; } if (props.viewEndpoint) { - dataset.viewEndpoint = props.viewEndpoint; + dataset.viewEndpoint = makeAbsolute(props.viewEndpoint); } if (props.eventEndpoint) { - dataset.eventEndpoint = props.eventEndpoint; + dataset.eventEndpoint = makeAbsolute(props.eventEndpoint); } if (props.sessionEndpoint) { - dataset.sessionEndpoint = props.sessionEndpoint; + dataset.sessionEndpoint = makeAbsolute(props.sessionEndpoint); } if (isDevelopment() && props.debug === false) { dataset.debug = 'false'; @@ -184,7 +184,7 @@ export function loadProps( if (props.endpoint) { dataset.endpoint = props.endpoint; } else if (props.basePath) { - dataset.endpoint = `${props.basePath}/insights`; + dataset.endpoint = makeAbsolute(`${props.basePath}/insights`); } return { @@ -193,3 +193,11 @@ export function loadProps( dataset, }; } + +function makeAbsolute(url: string): string { + return url.startsWith('http://') || + url.startsWith('https://') || + url.startsWith('/') + ? url + : `/${url}`; +} diff --git a/packages/web/src/vue/create-component.ts b/packages/web/src/vue/create-component.ts index 830aa9d..705881d 100644 --- a/packages/web/src/vue/create-component.ts +++ b/packages/web/src/vue/create-component.ts @@ -14,7 +14,10 @@ export function createComponent( const route = useRoute(); inject( { - ...props, + // trim out undefined values to avoid overriding config values + ...Object.fromEntries( + Object.entries(props).filter(([_, v]) => v !== undefined), + ), basePath: getBasePath(), // keep auto-tracking unless we have route support (Nuxt or vue-router). disableAutoTrack: Boolean(route),