diff --git a/README.md b/README.md index 131e2cd..005941e 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,9 @@ const { env, isDevelopment, isProduction } = require("std-env"); - `isColorSupported` - `nodeVersion` - `nodeMajorVersion` +- `isNode` +- `isDeno` +- `isBun` You can read more about how each flag works from [./src/flags.ts](./src/flags.ts). @@ -55,12 +58,12 @@ You can read more about how each flag works from [./src/flags.ts](./src/flags.ts You can use `isCI` and `platform` exports to detect it: ```ts -import { isCI, platform, platformInfo } from "std-env"; +import { isCI, provider, providerInfo } from "std-env"; console.log({ isCI, // true - platform, // "github_actions" - platformInfo, // { name: "github_actions", isCI: true } + provider, // "github_actions" + providerInfo, // { name: "github_actions", isCI: true } }); ``` @@ -75,7 +78,20 @@ console.log(detectProvider({ VERCEL: "1" })); List of well known providers can be found from [./src/providers.ts](./src/providers.ts). -## Platform agnotic env +## Runtime Detection + +`std-env` can automatically detect the current JavaScript runtime based on global variables, following the [WinterCG Runtime Keys proposal](https://runtime-keys.proposal.wintercg.org/): + +```ts +import { detectRuntime } from "std-env"; + +// "node" | "deno" | "bun" | "workerd" | "lagon" ... +console.log(detectRuntime()); +``` + +You can also use `isNode`, `isDeno`, and `isBun` helper methods. + +## Platform agnostic env `std-env` provides a lightweight proxy to access environment variables in a platform agnostic way. diff --git a/src/flags.ts b/src/flags.ts index bbdbea2..38543dc 100644 --- a/src/flags.ts +++ b/src/flags.ts @@ -2,6 +2,7 @@ import { detectProvider, ProviderName } from "./providers"; import { env, nodeENV } from "./env"; import { toBoolean } from "./_utils"; import { _process } from "./process"; +import { detectRuntime } from "./runtimes"; /** Value of process.platform */ export const platform = _process.platform || ""; @@ -55,3 +56,8 @@ export const isColorSupported = export const nodeVersion = (_process.versions?.node || "").replace(/^v/, "") || null; export const nodeMajorVersion = Number(nodeVersion?.split(".")[0]) || null; + +/** Detect the runtime type */ +export const isNode = detectRuntime() === "node"; +export const isDeno = detectRuntime() === "deno"; +export const isBun = detectRuntime() === "bun"; diff --git a/src/index.ts b/src/index.ts index fd3f4b7..3e4a366 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,3 +2,4 @@ export * from "./env"; export * from "./flags"; export * from "./process"; export * from "./providers"; +export * from "./runtimes"; diff --git a/src/runtimes.ts b/src/runtimes.ts new file mode 100644 index 0000000..5296416 --- /dev/null +++ b/src/runtimes.ts @@ -0,0 +1,63 @@ +/* eslint-disable no-var */ +declare global { + var EdgeRuntime: any; + var Netlify: any; + var Bun: any; + var Deno: any; + var __lagon__: any; + var fastly: any; +} + +// https://runtime-keys.proposal.wintercg.org/ +export type Runtime = + | "workerd" + | "deno" + | "lagon" + | "netlify" + | "node" + | "bun" + | "edge-light" + | "fastly" + | ""; + +// https://developers.cloudflare.com/workers/runtime-apis/web-standards/#navigatoruseragent +const CLOUDFLARE_WORKERS_NAVIGATOR = "Cloudflare-Workers"; + +// https://nodejs.org/api/process.html#processrelease +const NODE_PROCESS_RELEASE_NAME = "node"; + +export function detectRuntime(): Runtime { + if (typeof Netlify === "object") { + return "netlify"; + } + + if (typeof EdgeRuntime === "string") { + return "edge-light"; + } + + if (globalThis.navigator?.userAgent === CLOUDFLARE_WORKERS_NAVIGATOR) { + return "workerd"; + } + + if (globalThis.Deno) { + return "deno"; + } + + if (globalThis.__lagon__) { + return "lagon"; + } + + if (globalThis.process?.release?.name === NODE_PROCESS_RELEASE_NAME) { + return "node"; + } + + if (globalThis.Bun) { + return "bun"; + } + + if (globalThis.fastly) { + return "fastly"; + } + + return ""; +}