From e0b5c054eb0dd84e52b72245e2379c8078e35bca Mon Sep 17 00:00:00 2001 From: oritwoen <18102267+oritwoen@users.noreply.github.com> Date: Wed, 11 Mar 2026 12:49:50 +0100 Subject: [PATCH 1/2] fix(first-party): inject proxy endpoints for boolean/mock registry entries --- src/first-party/auto-inject.ts | 19 +++- test/unit/auto-inject.test.ts | 169 +++++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 test/unit/auto-inject.test.ts diff --git a/src/first-party/auto-inject.ts b/src/first-party/auto-inject.ts index 1d27a80cf..568ba0b49 100644 --- a/src/first-party/auto-inject.ts +++ b/src/first-party/auto-inject.ts @@ -51,14 +51,25 @@ export function autoInjectProxyEndpoints( ): void { for (const def of AUTO_INJECT_DEFS) { const entry = registry[def.registryKey] - if (!entry || typeof entry !== 'object') + if (!entry) continue - const config = (Array.isArray(entry) ? entry[0] : entry) as Record + let config: Record | undefined + if (entry === true || entry === 'mock') { + config = {} + } + else if (typeof entry === 'object') { + config = (Array.isArray(entry) ? entry[0] : entry) as Record + } + if (!config || config[def.configField]) continue - config[def.configField] = def.computeValue(collectPrefix, config) + const value = def.computeValue(collectPrefix, config) + + if (typeof entry === 'object') { + config[def.configField] = value + } // Propagate to runtimeConfig const rtScripts = runtimeConfig.public?.scripts as Record | undefined @@ -66,7 +77,7 @@ export function autoInjectProxyEndpoints( if (rtEntry && typeof rtEntry === 'object') { const rtConfig = Array.isArray(rtEntry) ? rtEntry[0] : rtEntry if (rtConfig) - rtConfig[def.configField] = config[def.configField] + rtConfig[def.configField] = value } } } diff --git a/test/unit/auto-inject.test.ts b/test/unit/auto-inject.test.ts new file mode 100644 index 000000000..b0910efee --- /dev/null +++ b/test/unit/auto-inject.test.ts @@ -0,0 +1,169 @@ +import { describe, expect, it } from 'vitest' +import { autoInjectProxyEndpoints } from '../../src/first-party/auto-inject' + +function makeRuntimeConfig(scripts: Record = {}) { + return { public: { scripts } } +} + +describe('autoInjectProxyEndpoints', () => { + describe('object entries', () => { + it('injects apiHost for posthog config object', () => { + const registry: any = { posthog: { apiKey: 'phc_test' } } + const rt = makeRuntimeConfig({ posthog: { apiKey: 'phc_test' } }) + + autoInjectProxyEndpoints(registry, rt, '/_proxy') + + expect(registry.posthog.apiHost).toBe('/_proxy/ph') + expect(rt.public.scripts.posthog.apiHost).toBe('/_proxy/ph') + }) + + it('injects endpoint for plausible config object', () => { + const registry: any = { plausibleAnalytics: { domain: 'example.com' } } + const rt = makeRuntimeConfig({ plausibleAnalytics: { domain: 'example.com' } }) + + autoInjectProxyEndpoints(registry, rt, '/_proxy') + + expect(registry.plausibleAnalytics.endpoint).toBe('/_proxy/plausible/api/event') + expect(rt.public.scripts.plausibleAnalytics.endpoint).toBe('/_proxy/plausible/api/event') + }) + + it('does not override existing config field', () => { + const registry: any = { posthog: { apiKey: 'phc_test', apiHost: 'https://custom.host' } } + const rt = makeRuntimeConfig({ posthog: { apiKey: 'phc_test', apiHost: 'https://custom.host' } }) + + autoInjectProxyEndpoints(registry, rt, '/_proxy') + + expect(registry.posthog.apiHost).toBe('https://custom.host') + expect(rt.public.scripts.posthog.apiHost).toBe('https://custom.host') + }) + + it('uses EU prefix when posthog region is eu', () => { + const registry: any = { posthog: { apiKey: 'phc_test', region: 'eu' } } + const rt = makeRuntimeConfig({ posthog: { apiKey: 'phc_test', region: 'eu' } }) + + autoInjectProxyEndpoints(registry, rt, '/_proxy') + + expect(registry.posthog.apiHost).toBe('/_proxy/ph-eu') + }) + }) + + describe('array entries', () => { + it('injects into first element of array entry', () => { + const registry: any = { posthog: [{ apiKey: 'phc_test' }, { partytown: true }] } + const rt = makeRuntimeConfig({ posthog: { apiKey: 'phc_test' } }) + + autoInjectProxyEndpoints(registry, rt, '/_proxy') + + expect(registry.posthog[0].apiHost).toBe('/_proxy/ph') + expect(rt.public.scripts.posthog.apiHost).toBe('/_proxy/ph') + }) + + it('skips empty array entries', () => { + const registry: any = { posthog: [] } + const rt = makeRuntimeConfig({ posthog: { apiKey: '' } }) + + autoInjectProxyEndpoints(registry, rt, '/_proxy') + + expect(rt.public.scripts.posthog.apiHost).toBeUndefined() + }) + }) + + describe('boolean entries', () => { + it('injects into runtimeConfig for posthog: true', () => { + const registry: any = { posthog: true } + const rt = makeRuntimeConfig({ posthog: { apiKey: '' } }) + + autoInjectProxyEndpoints(registry, rt, '/_proxy') + + expect(registry.posthog).toBe(true) + expect(rt.public.scripts.posthog.apiHost).toBe('/_proxy/ph') + }) + + it('injects into runtimeConfig for plausibleAnalytics: true', () => { + const registry: any = { plausibleAnalytics: true } + const rt = makeRuntimeConfig({ plausibleAnalytics: { domain: '' } }) + + autoInjectProxyEndpoints(registry, rt, '/_proxy') + + expect(rt.public.scripts.plausibleAnalytics.endpoint).toBe('/_proxy/plausible/api/event') + }) + + it('injects into runtimeConfig for umamiAnalytics: true', () => { + const registry: any = { umamiAnalytics: true } + const rt = makeRuntimeConfig({ umamiAnalytics: { websiteId: '' } }) + + autoInjectProxyEndpoints(registry, rt, '/_proxy') + + expect(rt.public.scripts.umamiAnalytics.hostUrl).toBe('/_proxy/umami') + }) + + it('injects into runtimeConfig for rybbitAnalytics: true', () => { + const registry: any = { rybbitAnalytics: true } + const rt = makeRuntimeConfig({ rybbitAnalytics: { siteId: '' } }) + + autoInjectProxyEndpoints(registry, rt, '/_proxy') + + expect(rt.public.scripts.rybbitAnalytics.analyticsHost).toBe('/_proxy/rybbit/api') + }) + + it('injects into runtimeConfig for databuddyAnalytics: true', () => { + const registry: any = { databuddyAnalytics: true } + const rt = makeRuntimeConfig({ databuddyAnalytics: { clientId: '' } }) + + autoInjectProxyEndpoints(registry, rt, '/_proxy') + + expect(rt.public.scripts.databuddyAnalytics.apiUrl).toBe('/_proxy/databuddy-api') + }) + }) + + describe('mock entries', () => { + it('injects into runtimeConfig for posthog: mock', () => { + const registry: any = { posthog: 'mock' } + const rt = makeRuntimeConfig({ posthog: { apiKey: '' } }) + + autoInjectProxyEndpoints(registry, rt, '/_proxy') + + expect(rt.public.scripts.posthog.apiHost).toBe('/_proxy/ph') + }) + }) + + describe('skipped entries', () => { + it('skips scripts not in AUTO_INJECT_DEFS', () => { + const registry: any = { googleAnalytics: { id: 'G-TEST' } } + const rt = makeRuntimeConfig({ googleAnalytics: { id: 'G-TEST' } }) + + autoInjectProxyEndpoints(registry, rt, '/_proxy') + + expect(rt.public.scripts.googleAnalytics).toEqual({ id: 'G-TEST' }) + }) + + it('skips falsy entries', () => { + const registry: any = { posthog: false } + const rt = makeRuntimeConfig() + + autoInjectProxyEndpoints(registry, rt, '/_proxy') + + expect(rt.public.scripts.posthog).toBeUndefined() + }) + + it('does not modify existing runtimeConfig for falsy entry', () => { + const registry: any = { posthog: false } + const rt = makeRuntimeConfig({ posthog: { existing: 'value' } }) + + autoInjectProxyEndpoints(registry, rt, '/_proxy') + + expect(rt.public.scripts.posthog).toEqual({ existing: 'value' }) + }) + }) + + describe('custom collectPrefix', () => { + it('uses custom prefix in computed values', () => { + const registry: any = { posthog: true } + const rt = makeRuntimeConfig({ posthog: { apiKey: '' } }) + + autoInjectProxyEndpoints(registry, rt, '/_analytics') + + expect(rt.public.scripts.posthog.apiHost).toBe('/_analytics/ph') + }) + }) +}) From 6e90d956788297123d45f6af5f1327e90534ee89 Mon Sep 17 00:00:00 2001 From: oritwoen <18102267+oritwoen@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:00:46 +0100 Subject: [PATCH 2/2] fix(first-party): respect runtime posthog region for shorthand entries --- src/first-party/auto-inject.ts | 11 +++++++---- test/unit/auto-inject.test.ts | 9 +++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/first-party/auto-inject.ts b/src/first-party/auto-inject.ts index 568ba0b49..0a57cdcd0 100644 --- a/src/first-party/auto-inject.ts +++ b/src/first-party/auto-inject.ts @@ -54,9 +54,15 @@ export function autoInjectProxyEndpoints( if (!entry) continue + const rtScripts = runtimeConfig.public?.scripts as Record | undefined + const rtEntry = rtScripts?.[def.registryKey] + const rtConfig = rtEntry && typeof rtEntry === 'object' + ? (Array.isArray(rtEntry) ? rtEntry[0] : rtEntry) + : undefined + let config: Record | undefined if (entry === true || entry === 'mock') { - config = {} + config = rtConfig || {} } else if (typeof entry === 'object') { config = (Array.isArray(entry) ? entry[0] : entry) as Record @@ -72,10 +78,7 @@ export function autoInjectProxyEndpoints( } // Propagate to runtimeConfig - const rtScripts = runtimeConfig.public?.scripts as Record | undefined - const rtEntry = rtScripts?.[def.registryKey] if (rtEntry && typeof rtEntry === 'object') { - const rtConfig = Array.isArray(rtEntry) ? rtEntry[0] : rtEntry if (rtConfig) rtConfig[def.configField] = value } diff --git a/test/unit/auto-inject.test.ts b/test/unit/auto-inject.test.ts index b0910efee..1730b3169 100644 --- a/test/unit/auto-inject.test.ts +++ b/test/unit/auto-inject.test.ts @@ -79,6 +79,15 @@ describe('autoInjectProxyEndpoints', () => { expect(rt.public.scripts.posthog.apiHost).toBe('/_proxy/ph') }) + it('uses EU prefix for posthog: true when runtime region is eu', () => { + const registry: any = { posthog: true } + const rt = makeRuntimeConfig({ posthog: { apiKey: '', region: 'eu' } }) + + autoInjectProxyEndpoints(registry, rt, '/_proxy') + + expect(rt.public.scripts.posthog.apiHost).toBe('/_proxy/ph-eu') + }) + it('injects into runtimeConfig for plausibleAnalytics: true', () => { const registry: any = { plausibleAnalytics: true } const rt = makeRuntimeConfig({ plausibleAnalytics: { domain: '' } })