Skip to content

Commit

Permalink
feat(client): detect browser usage (#101)
Browse files Browse the repository at this point in the history
  • Loading branch information
stainless-bot authored and rattrayalex committed Aug 9, 2023
1 parent e9ef3d2 commit f4cae3f
Showing 1 changed file with 65 additions and 2 deletions.
67 changes: 65 additions & 2 deletions src/core.ts
Expand Up @@ -635,12 +635,13 @@ type PlatformName =
| 'Android'
| `Other:${string}`
| 'Unknown';
type Browser = 'ie' | 'edge' | 'chrome' | 'firefox' | 'safari';
type PlatformProperties = {
'X-Stainless-Lang': 'js';
'X-Stainless-Package-Version': string;
'X-Stainless-OS': PlatformName;
'X-Stainless-Arch': Arch;
'X-Stainless-Runtime': 'node' | 'deno' | 'edge' | 'unknown';
'X-Stainless-Runtime': 'node' | 'deno' | 'edge' | `browser:${Browser}` | 'unknown';
'X-Stainless-Runtime-Version': string;
};
const getPlatformProperties = (): PlatformProperties => {
Expand Down Expand Up @@ -675,7 +676,20 @@ const getPlatformProperties = (): PlatformProperties => {
'X-Stainless-Runtime-Version': process.version,
};
}
// TODO add support for Cloudflare workers, browsers, etc.

const browserInfo = getBrowserInfo();
if (browserInfo) {
return {
'X-Stainless-Lang': 'js',
'X-Stainless-Package-Version': VERSION,
'X-Stainless-OS': 'Unknown',
'X-Stainless-Arch': 'unknown',
'X-Stainless-Runtime': `browser:${browserInfo.browser}`,
'X-Stainless-Runtime-Version': browserInfo.version,
};
}

// TODO add support for Cloudflare workers, etc.
return {
'X-Stainless-Lang': 'js',
'X-Stainless-Package-Version': VERSION,
Expand All @@ -686,6 +700,44 @@ const getPlatformProperties = (): PlatformProperties => {
};
};

type BrowserInfo = {
browser: Browser;
version: string;
};

declare const navigator: { userAgent: string } | undefined;

// Note: modified from https://github.com/JS-DevTools/host-environment/blob/b1ab79ecde37db5d6e163c050e54fe7d287d7c92/src/isomorphic.browser.ts
function getBrowserInfo(): BrowserInfo | null {
if (!navigator || typeof navigator === 'undefined') {
return null;
}

// NOTE: The order matters here!
const browserPatterns = [
{ key: 'edge' as const, pattern: /Edge(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
{ key: 'ie' as const, pattern: /MSIE(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
{ key: 'ie' as const, pattern: /Trident(?:.*rv\:(\d+)\.(\d+)(?:\.(\d+))?)?/ },
{ key: 'chrome' as const, pattern: /Chrome(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
{ key: 'firefox' as const, pattern: /Firefox(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
{ key: 'safari' as const, pattern: /(?:Version\W+(\d+)\.(\d+)(?:\.(\d+))?)?(?:\W+Mobile\S*)?\W+Safari/ },
];

// Find the FIRST matching browser
for (const { key, pattern } of browserPatterns) {
const match = pattern.exec(navigator.userAgent);
if (match) {
const major = match[1] || 0;
const minor = match[2] || 0;
const patch = match[3] || 0;

return { browser: key, version: `${major}.${minor}.${patch}` };
}
}

return null;
}

const normalizeArch = (arch: string): Arch => {
// Node docs:
// - https://nodejs.org/api/process.html#processarch
Expand Down Expand Up @@ -843,6 +895,17 @@ const uuid4 = () => {
});
};

export const isRunningInBrowser = () => {
return (
// @ts-ignore
typeof window !== 'undefined' &&
// @ts-ignore
typeof window.document !== 'undefined' &&
// @ts-ignore
typeof navigator !== 'undefined'
);
};

export interface HeadersProtocol {
get: (header: string) => string | null | undefined;
}
Expand Down

0 comments on commit f4cae3f

Please sign in to comment.