diff --git a/rollup.config.mjs b/rollup.config.mjs index 7c086e49..c16ce3d7 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -16,6 +16,12 @@ export default [ plugins: [ typescript({ compilerOptions: { + "lib": [ + "DOM", + "WebWorker", + "ESNext" + ], + "skipDefaultLibCheck": true, "module": "ESNext", "moduleResolution": "Node", "target": "ES2022", diff --git a/src/AzureAppConfigurationImpl.ts b/src/AzureAppConfigurationImpl.ts index 19a93d20..323ac2a8 100644 --- a/src/AzureAppConfigurationImpl.ts +++ b/src/AzureAppConfigurationImpl.ts @@ -9,8 +9,8 @@ import { JsonKeyValueAdapter } from "./JsonKeyValueAdapter"; import { KeyFilter } from "./KeyFilter"; import { LabelFilter } from "./LabelFilter"; import { AzureKeyVaultKeyValueAdapter } from "./keyvault/AzureKeyVaultKeyValueAdapter"; -import { CorrelationContextHeaderName, RequestTracingDisabledEnvironmentVariable } from "./requestTracing/constants"; -import { createCorrelationContextHeader } from "./requestTracing/utils"; +import { CorrelationContextHeaderName } from "./requestTracing/constants"; +import { createCorrelationContextHeader, requestTracingEnabled } from "./requestTracing/utils"; export class AzureAppConfigurationImpl extends Map implements AzureAppConfiguration { private adapters: IKeyValueAdapter[] = []; @@ -28,11 +28,8 @@ export class AzureAppConfigurationImpl extends Map implements A ) { super(); // Enable request tracing if not opt-out - const requestTracingDisabledEnv = process.env[RequestTracingDisabledEnvironmentVariable]; - if (requestTracingDisabledEnv && requestTracingDisabledEnv.toLowerCase() === "true") { - this.requestTracingEnabled = false; - } else { - this.requestTracingEnabled = true; + this.requestTracingEnabled = requestTracingEnabled(); + if (this.requestTracingEnabled) { this.enableRequestTracing(); } diff --git a/src/requestTracing/constants.ts b/src/requestTracing/constants.ts index 412f74c7..a08e36f4 100644 --- a/src/requestTracing/constants.ts +++ b/src/requestTracing/constants.ts @@ -24,7 +24,10 @@ export enum HostType { AzureWebApp = "AzureWebApp", ContainerApp = "ContainerApp", Kubernetes = "Kubernetes", - ServiceFabric = "ServiceFabric" + ServiceFabric = "ServiceFabric", + // Client-side + Browser = "Web", + WebWorker = "WebWorker" } // Environment variables to identify Host type. diff --git a/src/requestTracing/utils.ts b/src/requestTracing/utils.ts index 29ec0a39..95483bfa 100644 --- a/src/requestTracing/utils.ts +++ b/src/requestTracing/utils.ts @@ -14,6 +14,7 @@ import { KubernetesEnvironmentVariable, NodeJSDevEnvironmentVariableValue, NodeJSEnvironmentVariable, + RequestTracingDisabledEnvironmentVariable, RequestType, RequestTypeKey, ServiceFabricEnvironmentVariable @@ -53,26 +54,65 @@ export function createCorrelationContextHeader(options: AzureAppConfigurationOpt return contextParts.join(","); } +export function requestTracingEnabled(): boolean { + const requestTracingDisabledEnv = getEnvironmentVariable(RequestTracingDisabledEnvironmentVariable); + const disabled = requestTracingDisabledEnv?.toLowerCase() === "true"; + return !disabled; +} + +function getEnvironmentVariable(name: string) { + // Make it compatible with non-Node.js runtime + if (typeof process?.env === "object") { + return process.env[name]; + } else { + return undefined; + } +} + function getHostType(): string | undefined { let hostType: string | undefined; - if (process.env[AzureFunctionEnvironmentVariable]) { + if (getEnvironmentVariable(AzureFunctionEnvironmentVariable)) { hostType = HostType.AzureFunction; - } else if (process.env[AzureWebAppEnvironmentVariable]) { + } else if (getEnvironmentVariable(AzureWebAppEnvironmentVariable)) { hostType = HostType.AzureWebApp; - } else if (process.env[ContainerAppEnvironmentVariable]) { + } else if (getEnvironmentVariable(ContainerAppEnvironmentVariable)) { hostType = HostType.ContainerApp; - } else if (process.env[KubernetesEnvironmentVariable]) { + } else if (getEnvironmentVariable(KubernetesEnvironmentVariable)) { hostType = HostType.Kubernetes; - } else if (process.env[ServiceFabricEnvironmentVariable]) { + } else if (getEnvironmentVariable(ServiceFabricEnvironmentVariable)) { hostType = HostType.ServiceFabric; + } else if (isBrowser()) { + hostType = HostType.Browser; + } else if (isWebWorker()) { + hostType = HostType.WebWorker; } return hostType; } function isDevEnvironment(): boolean { - const envType = process.env[NodeJSEnvironmentVariable]; + const envType = getEnvironmentVariable(NodeJSEnvironmentVariable); if (NodeJSDevEnvironmentVariableValue === envType?.toLowerCase()) { return true; } return false; +} + +function isBrowser() { + // https://developer.mozilla.org/en-US/docs/Web/API/Window + const isWindowDefinedAsExpected = typeof window === "object" && typeof Window === "function" && window instanceof Window; + // https://developer.mozilla.org/en-US/docs/Web/API/Document + const isDocumentDefinedAsExpected = typeof document === "object" && typeof Document === "function" && document instanceof Document; + + return isWindowDefinedAsExpected && isDocumentDefinedAsExpected; +} + +function isWebWorker() { + // https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope + const workerGlobalScopeDefined = typeof WorkerGlobalScope !== "undefined"; + // https://developer.mozilla.org/en-US/docs/Web/API/WorkerNavigator + const isNavigatorDefinedAsExpected = typeof navigator === "object" && typeof WorkerNavigator !== "function" && navigator instanceof WorkerNavigator; + // https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#importing_scripts_and_libraries + const importScriptsAsGlobalFunction = typeof importScripts === "function"; + + return workerGlobalScopeDefined && importScriptsAsGlobalFunction && isNavigatorDefinedAsExpected; } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 1013b7de..395c4d54 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,11 @@ { "compilerOptions": { + "lib": [ + "DOM", + "WebWorker", + "ESNext" + ], + "skipDefaultLibCheck": true, "module": "ESNext", "moduleResolution": "Node", "target": "ES2022",