diff --git a/posthog-core/src/types.ts b/posthog-core/src/types.ts index 53681162..d3d833d0 100644 --- a/posthog-core/src/types.ts +++ b/posthog-core/src/types.ts @@ -133,3 +133,5 @@ export type PostHogFlagsAndPayloadsResponse = { } export type JsonType = string | number | boolean | null | { [key: string]: JsonType } | Array + +export type FetchLike = (url: string, options: PostHogFetchOptions) => Promise diff --git a/posthog-core/src/utils.ts b/posthog-core/src/utils.ts index 8056906a..dfa715d9 100644 --- a/posthog-core/src/utils.ts +++ b/posthog-core/src/utils.ts @@ -1,3 +1,5 @@ +import { FetchLike } from './types' + export function assert(truthyValue: any, message: string): void { if (!truthyValue) { throw new Error(message) @@ -58,3 +60,7 @@ export function safeSetTimeout(fn: () => void, timeout: number): any { export const isPromise = (obj: any): obj is Promise => { return obj && typeof obj.then === 'function' } + +export function getFetch(): FetchLike | undefined { + return typeof fetch !== 'undefined' ? fetch : typeof global.fetch !== 'undefined' ? global.fetch : undefined +} diff --git a/posthog-node/src/fetch.ts b/posthog-node/src/fetch.ts index 52bafc22..ff70594f 100644 --- a/posthog-node/src/fetch.ts +++ b/posthog-node/src/fetch.ts @@ -7,14 +7,10 @@ * See https://github.com/PostHog/posthog-js-lite/issues/127 for more info */ -import { PostHogFetchOptions, PostHogFetchResponse } from 'posthog-core/src' +import { FetchLike, PostHogFetchOptions, PostHogFetchResponse } from 'posthog-core/src' +import { getFetch } from 'posthog-core/src/utils' -type FetchLike = (url: string, options: PostHogFetchOptions) => Promise - -let _fetch: FetchLike | undefined = - // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error - // @ts-ignore - typeof fetch !== 'undefined' ? fetch : typeof global.fetch !== 'undefined' ? global.fetch : undefined +let _fetch: FetchLike | undefined = getFetch() if (!_fetch) { // eslint-disable-next-line @typescript-eslint/no-var-requires diff --git a/posthog-web/CHANGELOG.md b/posthog-web/CHANGELOG.md index 7caa150c..1246e5b2 100644 --- a/posthog-web/CHANGELOG.md +++ b/posthog-web/CHANGELOG.md @@ -1,5 +1,11 @@ # Next +# 3.2.1 - 2025-01-17 + +## Fixed + +1. fix: check if window and fetch are available before using on web env + # 3.2.0 - 2024-12-12 ## Changed diff --git a/posthog-web/package.json b/posthog-web/package.json index 73a1765a..9006e645 100644 --- a/posthog-web/package.json +++ b/posthog-web/package.json @@ -1,6 +1,6 @@ { "name": "posthog-js-lite", - "version": "3.2.0", + "version": "3.2.1", "main": "lib/index.cjs.js", "module": "lib/index.esm.js", "types": "lib/index.d.ts", diff --git a/posthog-web/src/context.ts b/posthog-web/src/context.ts index 10a9de77..13ffe7d2 100644 --- a/posthog-web/src/context.ts +++ b/posthog-web/src/context.ts @@ -1,13 +1,14 @@ import { utils } from '../../posthog-core' import { version } from '../package.json' -export function getContext(window: Window): any { +export function getContext(window: Window | undefined): any { let context = {} - if (window.navigator) { + if (window?.navigator) { const userAgent = window.navigator.userAgent + const osValue = os(window) context = { ...context, - $os: os(window), + ...(osValue !== undefined && { $os: osValue }), $browser: browser(userAgent, window.navigator.vendor, !!(window as any).opera), $referrer: window.document.referrer, $referring_domain: referringDomain(window.document.referrer), @@ -21,6 +22,7 @@ export function getContext(window: Window): any { $screen_dpr: window.devicePixelRatio, } } + context = { ...context, $lib: 'js', @@ -114,7 +116,10 @@ function browserVersion(userAgent: string, vendor: string, opera: boolean): numb return parseFloat(matches[matches.length - 2]) } -function os(window: Window): string { +function os(window: Window | undefined): string | undefined { + if (!window?.navigator) { + return undefined + } const a = window.navigator.userAgent if (/Windows/i.test(a)) { if (/Phone/.test(a) || /WPDesktop/.test(a)) { @@ -134,7 +139,7 @@ function os(window: Window): string { } else if (/CrOS/.test(a)) { return 'Chrome OS' } else { - return '' + return undefined } } diff --git a/posthog-web/src/posthog-web.ts b/posthog-web/src/posthog-web.ts index ac4d4988..64499d46 100644 --- a/posthog-web/src/posthog-web.ts +++ b/posthog-web/src/posthog-web.ts @@ -8,6 +8,7 @@ import { getContext } from './context' import { PostHogStorage, getStorage } from './storage' import { version } from '../package.json' import { PostHogOptions } from './types' +import { getFetch } from 'posthog-core/src/utils' export class PostHog extends PostHogCore { private _storage: PostHogStorage @@ -19,7 +20,8 @@ export class PostHog extends PostHogCore { // posthog-js stores options in one object on this._storageKey = options?.persistence_name ? `ph_${options.persistence_name}` : `ph_${apiKey}_posthog` - this._storage = getStorage(options?.persistence || 'localStorage', window) + + this._storage = getStorage(options?.persistence || 'localStorage', this.getWindow()) this.setupBootstrap(options) if (options?.preloadFeatureFlags !== false) { @@ -27,6 +29,10 @@ export class PostHog extends PostHogCore { } } + private getWindow(): Window | undefined { + return typeof window !== 'undefined' ? window : undefined + } + getPersistedProperty(key: PostHogPersistedProperty): T | undefined { if (!this._storageCache) { this._storageCache = JSON.parse(this._storage.getItem(this._storageKey) || '{}') || {} @@ -50,7 +56,14 @@ export class PostHog extends PostHogCore { } fetch(url: string, options: PostHogFetchOptions): Promise { - return window.fetch(url, options) + const fetchFn = getFetch() + + if (!fetchFn) { + // error will be handled by the caller (fetchWithRetry) + return Promise.reject(new Error('Fetch API is not available in this environment.')) + } + + return fetchFn(url, options) } getLibraryId(): string { @@ -68,7 +81,7 @@ export class PostHog extends PostHogCore { getCommonEventProperties(): any { return { ...super.getCommonEventProperties(), - ...getContext(window), + ...getContext(this.getWindow()), } } } diff --git a/posthog-web/src/storage.ts b/posthog-web/src/storage.ts index 5f3d8317..f9722dfe 100644 --- a/posthog-web/src/storage.ts +++ b/posthog-web/src/storage.ts @@ -93,9 +93,6 @@ const createStorageLike = (store: any): PostHogStorage => { } const checkStoreIsSupported = (storage: PostHogStorage, key = '__mplssupport__'): boolean => { - if (!window) { - return false - } try { const val = 'xyz' storage.setItem(key, val)