Compare commits
	
		
			2 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8514c4def0 | |||
| aeac92f3fd | 
							
								
								
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
The MIT License (MIT)
 | 
					The MIT License (MIT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Copyright (c) 2015 Lossless GmbH
 | 
					Copyright (c) 2015 Task Venture Capital GmbH
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
of this software and associated documentation files (the "Software"), to deal
 | 
					of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								changelog.md
									
									
									
									
									
								
							@@ -1,5 +1,16 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2025-11-01 - 6.0.0 - BREAKING CHANGE(Smartenv)
 | 
				
			||||||
 | 
					Add Deno and Bun runtime detection, introduce getSafeModuleFor API, update docs and tests, and make isNode semantics Node-only (breaking change)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Implement runtime detection for Deno and Bun; runtimeEnv now returns one of 'node' | 'deno' | 'bun' | 'browser'.
 | 
				
			||||||
 | 
					- Change isNode to be true only for Node.js; add isDeno and isBun accessors. This is a breaking change in behavior for code that relied on isNode including Deno/Bun.
 | 
				
			||||||
 | 
					- Add getSafeModuleFor(target, moduleNameOrUrl, getFunction?) API to load modules conditionally for single, multiple or 'server' runtimes. Existing helpers getSafeNodeModule and getSafeWebModule updated to work with wider runtimes.
 | 
				
			||||||
 | 
					- Add runtime-specific version getters (nodeVersion, denoVersion, bunVersion) and update printEnv output accordingly.
 | 
				
			||||||
 | 
					- Expand and add tests for Node, Deno, Bun and Browser environments (tests/* files).
 | 
				
			||||||
 | 
					- Update documentation (readme.md and readme.hints.md) to describe detection order, new API and migration notes from 4.x to 5.x/6.x.
 | 
				
			||||||
 | 
					- Bump devDependencies (tsbuild, tsrun, tstest) and include an updated deno.lock.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## [5.0.13] - 2025-07-28
 | 
					## [5.0.13] - 2025-07-28
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Fixed
 | 
					### Fixed
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@push.rocks/smartenv",
 | 
					  "name": "@push.rocks/smartenv",
 | 
				
			||||||
  "version": "5.0.13",
 | 
					  "version": "6.0.0",
 | 
				
			||||||
  "description": "A module for storing and accessing environment details across different platforms.",
 | 
					  "description": "A module for storing and accessing environment details across different platforms.",
 | 
				
			||||||
  "main": "dist_ts/index.js",
 | 
					  "main": "dist_ts/index.js",
 | 
				
			||||||
  "typings": "dist_ts/index.d.ts",
 | 
					  "typings": "dist_ts/index.d.ts",
 | 
				
			||||||
@@ -37,10 +37,10 @@
 | 
				
			|||||||
    "@push.rocks/smartpromise": "^4.0.2"
 | 
					    "@push.rocks/smartpromise": "^4.0.2"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@git.zone/tsbuild": "^2.1.72",
 | 
					    "@git.zone/tsbuild": "^2.6.8",
 | 
				
			||||||
    "@git.zone/tsbundle": "^2.0.15",
 | 
					    "@git.zone/tsbundle": "^2.0.15",
 | 
				
			||||||
    "@git.zone/tsrun": "^1.2.44",
 | 
					    "@git.zone/tsrun": "^1.6.2",
 | 
				
			||||||
    "@git.zone/tstest": "^2.3.2",
 | 
					    "@git.zone/tstest": "^2.7.0",
 | 
				
			||||||
    "@types/node": "^22.0.0"
 | 
					    "@types/node": "^22.0.0"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "private": false,
 | 
					  "private": false,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4444
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4444
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -4,20 +4,76 @@
 | 
				
			|||||||
- Single main class `Smartenv` that provides all functionality
 | 
					- Single main class `Smartenv` that provides all functionality
 | 
				
			||||||
- Uses dependency injection pattern with plugins imported from smartenv.plugins.ts
 | 
					- Uses dependency injection pattern with plugins imported from smartenv.plugins.ts
 | 
				
			||||||
- Utilizes @push.rocks/smartpromise for async operations
 | 
					- Utilizes @push.rocks/smartpromise for async operations
 | 
				
			||||||
 | 
					- **BREAKING CHANGE**: `runtimeEnv` now returns `'node' | 'deno' | 'bun' | 'browser'` (previously only 'node' | 'browser')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Runtime Detection System
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Detection Order (Critical!)
 | 
				
			||||||
 | 
					The order matters to avoid false positives:
 | 
				
			||||||
 | 
					1. **Deno** - Check `globalThis.Deno?.version` first (Deno has a `process` object for compatibility)
 | 
				
			||||||
 | 
					2. **Bun** - Check `globalThis.Bun?.version` second (Bun also has a `process` object)
 | 
				
			||||||
 | 
					3. **Node.js** - Check `globalThis.process?.versions?.node` third (must be specific to avoid Deno/Bun)
 | 
				
			||||||
 | 
					4. **Browser** - Check `globalThis.window && globalThis.document` as fallback
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Runtime Properties
 | 
				
			||||||
 | 
					- `runtimeEnv: TRuntimeType` - Returns 'node' | 'deno' | 'bun' | 'browser'
 | 
				
			||||||
 | 
					- `isNode: boolean` - True only for Node.js (excludes Deno and Bun)
 | 
				
			||||||
 | 
					- `isDeno: boolean` - True only for Deno runtime
 | 
				
			||||||
 | 
					- `isBun: boolean` - True only for Bun runtime
 | 
				
			||||||
 | 
					- `isBrowser: boolean` - True only for browser environment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Version Getters
 | 
				
			||||||
 | 
					- `nodeVersion: string` - Node.js version (returns 'undefined' in other runtimes)
 | 
				
			||||||
 | 
					- `denoVersion: string` - Deno version (returns 'undefined' in other runtimes)
 | 
				
			||||||
 | 
					- `bunVersion: string` - Bun version (returns 'undefined' in other runtimes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Module Loading API
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### New: getSafeModuleFor()
 | 
				
			||||||
 | 
					Flexible module loading that supports runtime targeting:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					// Load for specific runtime
 | 
				
			||||||
 | 
					await env.getSafeModuleFor('node', 'path')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Load for multiple runtimes
 | 
				
			||||||
 | 
					await env.getSafeModuleFor(['node', 'deno'], 'path')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Load for all server-side runtimes (shorthand for ['node', 'deno', 'bun'])
 | 
				
			||||||
 | 
					await env.getSafeModuleFor('server', 'path')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Browser loading requires getFunction
 | 
				
			||||||
 | 
					await env.getSafeModuleFor('browser', 'url', () => window.someLibrary)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Parameters:**
 | 
				
			||||||
 | 
					- `target: TRuntimeTarget | TRuntimeTarget[]` - Runtime(s) to load for
 | 
				
			||||||
 | 
					- `moduleNameOrUrl: string` - Module name or URL
 | 
				
			||||||
 | 
					- `getFunction?: () => any` - Required for browser module loading
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Returns:** Module or `undefined` if runtime doesn't match
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Legacy Methods (Still Supported)
 | 
				
			||||||
 | 
					- `getSafeNodeModule()` - Now works for Node.js, Deno, and Bun
 | 
				
			||||||
 | 
					- `getSafeWebModule()` - Browser-only module loading
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Key Implementation Details
 | 
					## Key Implementation Details
 | 
				
			||||||
- Runtime detection based on checking if `process` is defined
 | 
					- Dynamic module loading using Function constructor for server-side modules
 | 
				
			||||||
- Dynamic module loading using Function constructor for Node.js modules
 | 
					 | 
				
			||||||
- Script tag injection for browser module loading with duplicate prevention
 | 
					- Script tag injection for browser module loading with duplicate prevention
 | 
				
			||||||
- OS detection uses the native Node.js 'os' module loaded dynamically
 | 
					- OS detection uses the native 'os' module loaded dynamically (works in Node.js, Deno, Bun)
 | 
				
			||||||
 | 
					- All detection uses `globalThis` for robustness across environments
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Testing Approach
 | 
					## Testing Approach
 | 
				
			||||||
- Tests use @git.zone/tstest with tap-based testing
 | 
					- Tests use @git.zone/tstest with tap-based testing across all runtimes
 | 
				
			||||||
- Test file demonstrates OS detection and CI environment detection
 | 
					- `test.node.ts` - Node.js specific tests, verifies it's not confused with Deno/Bun
 | 
				
			||||||
- Tests can run in both Node.js and browser environments
 | 
					- `test.deno.ts` - Deno runtime tests
 | 
				
			||||||
 | 
					- `test.bun.ts` - Bun runtime tests
 | 
				
			||||||
 | 
					- `test.chrome.ts` - Browser environment tests
 | 
				
			||||||
 | 
					- Each test file verifies proper runtime detection and module loading
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Important Notes
 | 
					## Important Notes
 | 
				
			||||||
- The `getSafeNodeModule` uses dynamic import via Function constructor to avoid bundler issues
 | 
					- The `getSafeNodeModule` uses dynamic import via Function constructor to avoid bundler issues
 | 
				
			||||||
- Browser module loading tracks loaded scripts to prevent duplicate loads
 | 
					- Browser module loading tracks loaded scripts to prevent duplicate loads
 | 
				
			||||||
- All OS detection methods are async and return false in browser environments
 | 
					- All OS detection methods are async and return false in browser environments
 | 
				
			||||||
- The package is isomorphic and designed for use in both Node.js and browser contexts
 | 
					- The package is isomorphic and designed for use in all four runtime contexts
 | 
				
			||||||
 | 
					- Runtime detection checks globals in specific order to avoid false positives from compatibility layers
 | 
				
			||||||
							
								
								
									
										635
									
								
								readme.md
									
									
									
									
									
								
							
							
						
						
									
										635
									
								
								readme.md
									
									
									
									
									
								
							@@ -1,241 +1,600 @@
 | 
				
			|||||||
# @push.rocks/smartenv
 | 
					# @push.rocks/smartenv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A cross-platform TypeScript library for detecting and managing runtime environments. It provides comprehensive environment detection capabilities and safe module loading for both Node.js and browser contexts.
 | 
					> 🚀 **Universal JavaScript Runtime Detection** - One library for Node.js, Deno, Bun, and Browser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A powerful TypeScript library that provides comprehensive runtime environment detection and safe module loading across **all major JavaScript runtimes**. Write once, run everywhere with confidence.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Why smartenv?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Modern JavaScript runs in many environments - Node.js, Deno, Bun, and browsers. Writing isomorphic code that works everywhere is challenging. **smartenv** solves this by providing:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- ✅ **Accurate runtime detection** - Distinguishes Node.js from Deno, Bun, and browsers without false positives
 | 
				
			||||||
 | 
					- ✅ **Smart module loading** - Load the right modules for each runtime automatically
 | 
				
			||||||
 | 
					- ✅ **Platform detection** - Detect macOS, Linux, Windows, and CI environments
 | 
				
			||||||
 | 
					- ✅ **Zero dependencies** (except @push.rocks/smartpromise)
 | 
				
			||||||
 | 
					- ✅ **Full TypeScript support** with complete type definitions
 | 
				
			||||||
 | 
					- ✅ **Battle-tested** - Comprehensive test suite across all runtimes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Install
 | 
					## Install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To install `@push.rocks/smartenv`, you need Node.js and pnpm installed. Then, run the following command:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
pnpm install @push.rocks/smartenv --save
 | 
					pnpm install @push.rocks/smartenv --save
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Usage
 | 
					```bash
 | 
				
			||||||
 | 
					npm install @push.rocks/smartenv --save
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`@push.rocks/smartenv` is a powerful utility for managing and accessing environment-specific information within your application. It enables your code to adapt seamlessly to different environments such as development, testing, and production.
 | 
					## Quick Start
 | 
				
			||||||
 | 
					 | 
				
			||||||
### Getting Started
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
First, import the `Smartenv` class from the package:
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					```typescript
 | 
				
			||||||
import { Smartenv } from '@push.rocks/smartenv';
 | 
					import { Smartenv } from '@push.rocks/smartenv';
 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Initializing Smartenv
 | 
					const env = new Smartenv();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Create an instance of `Smartenv` to access all environment detection and module loading features:
 | 
					// Detect the runtime
 | 
				
			||||||
 | 
					console.log(env.runtimeEnv); // 'node' | 'deno' | 'bun' | 'browser'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					// Load modules safely for your runtime
 | 
				
			||||||
const smartEnv = new Smartenv();
 | 
					const pathModule = await env.getSafeModuleFor('server', 'path');
 | 
				
			||||||
 | 
					if (pathModule) {
 | 
				
			||||||
 | 
					  console.log('Path module loaded!');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Check specific runtimes
 | 
				
			||||||
 | 
					if (env.isNode) {
 | 
				
			||||||
 | 
					  console.log(`Running on Node.js ${env.nodeVersion}`);
 | 
				
			||||||
 | 
					} else if (env.isDeno) {
 | 
				
			||||||
 | 
					  console.log(`Running on Deno ${env.denoVersion}`);
 | 
				
			||||||
 | 
					} else if (env.isBun) {
 | 
				
			||||||
 | 
					  console.log(`Running on Bun ${env.bunVersion}`);
 | 
				
			||||||
 | 
					} else {
 | 
				
			||||||
 | 
					  console.log(`Running in ${env.userAgent}`);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Core Features
 | 
					## Core Features
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- **Runtime Environment Detection**: Instantly detect whether your code is running in Node.js or browser
 | 
					### 🎯 Multi-Runtime Detection
 | 
				
			||||||
- **Operating System Detection**: Identify Mac, Windows, or Linux platforms in Node.js environments
 | 
					 | 
				
			||||||
- **CI Environment Detection**: Detect if running in a continuous integration environment
 | 
					 | 
				
			||||||
- **Safe Module Loading**: Load modules conditionally based on the runtime environment
 | 
					 | 
				
			||||||
- **Browser Information**: Access user agent information in browser contexts
 | 
					 | 
				
			||||||
- **Node.js Version**: Get the current Node.js version when running in Node.js
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
## API Reference
 | 
					Accurately detects all major JavaScript runtimes using proper detection order to avoid false positives:
 | 
				
			||||||
 | 
					 | 
				
			||||||
### Environment Detection
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### `isNode: boolean`
 | 
					 | 
				
			||||||
Returns `true` if running in a Node.js environment.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					```typescript
 | 
				
			||||||
if (smartEnv.isNode) {
 | 
					const env = new Smartenv();
 | 
				
			||||||
  console.log('Running in Node.js');
 | 
					
 | 
				
			||||||
}
 | 
					// Runtime type - returns one of: 'node' | 'deno' | 'bun' | 'browser'
 | 
				
			||||||
 | 
					console.log(env.runtimeEnv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Boolean checks for each runtime
 | 
				
			||||||
 | 
					env.isNode;     // true only in Node.js
 | 
				
			||||||
 | 
					env.isDeno;     // true only in Deno
 | 
				
			||||||
 | 
					env.isBun;      // true only in Bun
 | 
				
			||||||
 | 
					env.isBrowser;  // true only in browser
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### `isBrowser: boolean`
 | 
					**Why detection order matters:** Deno and Bun provide `process` objects for Node.js compatibility. smartenv checks for `Deno` and `Bun` globals first, then `process.versions.node`, ensuring accurate detection.
 | 
				
			||||||
Returns `true` if running in a browser environment.
 | 
					
 | 
				
			||||||
 | 
					### 📦 Smart Module Loading
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The new `getSafeModuleFor()` API lets you target specific runtimes or groups:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					```typescript
 | 
				
			||||||
if (smartEnv.isBrowser) {
 | 
					// Load for a specific runtime
 | 
				
			||||||
  console.log('Running in browser');
 | 
					const fsNode = await env.getSafeModuleFor('node', 'fs');
 | 
				
			||||||
}
 | 
					
 | 
				
			||||||
 | 
					// Load for Deno (requires 'node:' prefix for Node.js built-ins)
 | 
				
			||||||
 | 
					const fsDeno = await env.getSafeModuleFor('deno', 'node:path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Load for all server-side runtimes (Node.js + Deno + Bun)
 | 
				
			||||||
 | 
					const pathModule = await env.getSafeModuleFor('server', 'path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Load for multiple specific runtimes
 | 
				
			||||||
 | 
					const crypto = await env.getSafeModuleFor(['node', 'bun'], 'crypto');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Browser module loading
 | 
				
			||||||
 | 
					const jQuery = await env.getSafeModuleFor(
 | 
				
			||||||
 | 
					  'browser',
 | 
				
			||||||
 | 
					  'https://code.jquery.com/jquery-3.6.0.min.js',
 | 
				
			||||||
 | 
					  () => window.jQuery
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### `runtimeEnv: string`
 | 
					**Target options:**
 | 
				
			||||||
Returns the runtime environment as a string ('node' or 'browser').
 | 
					- `'node'` - Node.js only
 | 
				
			||||||
 | 
					- `'deno'` - Deno only
 | 
				
			||||||
 | 
					- `'bun'` - Bun only
 | 
				
			||||||
 | 
					- `'browser'` - Browser only
 | 
				
			||||||
 | 
					- `'server'` - Shorthand for `['node', 'deno', 'bun']`
 | 
				
			||||||
 | 
					- `['node', 'deno']` - Array of specific runtimes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If the current runtime doesn't match the target, the method returns `undefined` and logs a warning.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 🖥️ Platform Detection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Detect operating systems in server-side runtimes (Node.js, Deno, Bun):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					```typescript
 | 
				
			||||||
console.log(`Runtime: ${smartEnv.runtimeEnv}`);
 | 
					const env = new Smartenv();
 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### `isCI: boolean`
 | 
					// Async OS detection
 | 
				
			||||||
Returns `true` if running in a CI environment (checks for CI environment variable).
 | 
					const isMac = await env.isMacAsync();       // macOS
 | 
				
			||||||
 | 
					const isLinux = await env.isLinuxAsync();   // Linux
 | 
				
			||||||
 | 
					const isWindows = await env.isWindowsAsync(); // Windows
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					 | 
				
			||||||
if (smartEnv.isCI) {
 | 
					 | 
				
			||||||
  console.log('Running in CI environment');
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Platform Detection (Node.js only)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### `isMacAsync(): Promise<boolean>`
 | 
					 | 
				
			||||||
Asynchronously checks if running on macOS.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```typescript
 | 
					 | 
				
			||||||
const isMac = await smartEnv.isMacAsync();
 | 
					 | 
				
			||||||
if (isMac) {
 | 
					if (isMac) {
 | 
				
			||||||
  console.log('Running on macOS');
 | 
					  console.log('Running on macOS');
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### `isWindowsAsync(): Promise<boolean>`
 | 
					### 🔢 Version Information
 | 
				
			||||||
Asynchronously checks if running on Windows.
 | 
					
 | 
				
			||||||
 | 
					Get version strings for each runtime:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					```typescript
 | 
				
			||||||
const isWindows = await smartEnv.isWindowsAsync();
 | 
					const env = new Smartenv();
 | 
				
			||||||
if (isWindows) {
 | 
					
 | 
				
			||||||
  console.log('Running on Windows');
 | 
					// Returns version string or 'undefined' if not in that runtime
 | 
				
			||||||
 | 
					env.nodeVersion;  // e.g., 'v20.10.0'
 | 
				
			||||||
 | 
					env.denoVersion;  // e.g., '1.40.0'
 | 
				
			||||||
 | 
					env.bunVersion;   // e.g., '1.0.20'
 | 
				
			||||||
 | 
					env.userAgent;    // Browser user agent string
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 🏗️ CI Detection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Detect if running in a continuous integration environment:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					const env = new Smartenv();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (env.isCI) {
 | 
				
			||||||
 | 
					  console.log('Running in CI environment');
 | 
				
			||||||
 | 
					  // Enable extended test suite, different build config, etc.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## API Reference
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Runtime Detection Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `runtimeEnv: TRuntimeType`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Returns the detected runtime as a string.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Type:** `'node' | 'deno' | 'bun' | 'browser'`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					const env = new Smartenv();
 | 
				
			||||||
 | 
					console.log(env.runtimeEnv); // 'node', 'deno', 'bun', or 'browser'
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `isNode: boolean`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`true` if running in Node.js (specifically checks for `process.versions.node`).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					if (env.isNode) {
 | 
				
			||||||
 | 
					  console.log('Node.js environment');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `isDeno: boolean`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`true` if running in Deno (checks for `Deno` global).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					if (env.isDeno) {
 | 
				
			||||||
 | 
					  console.log('Deno environment');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `isBun: boolean`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`true` if running in Bun (checks for `Bun` global).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					if (env.isBun) {
 | 
				
			||||||
 | 
					  console.log('Bun environment');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `isBrowser: boolean`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`true` if running in a browser environment.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					if (env.isBrowser) {
 | 
				
			||||||
 | 
					  console.log('Browser environment');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `isCI: boolean`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`true` if running in a CI environment (checks `process.env.CI` in server runtimes).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					if (env.isCI) {
 | 
				
			||||||
 | 
					  // CI-specific logic
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Version Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `nodeVersion: string`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Node.js version string. Returns `'undefined'` if not in Node.js.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					console.log(env.nodeVersion); // 'v20.10.0'
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `denoVersion: string`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Deno version string. Returns `'undefined'` if not in Deno.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					console.log(env.denoVersion); // '1.40.0'
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `bunVersion: string`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Bun version string. Returns `'undefined'` if not in Bun.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					console.log(env.bunVersion); // '1.0.20'
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `userAgent: string`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Browser user agent string. Returns `'undefined'` if not in browser.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					console.log(env.userAgent); // 'Mozilla/5.0...'
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Platform Detection Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `isMacAsync(): Promise<boolean>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Asynchronously checks if running on macOS. Works in Node.js, Deno, and Bun.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					const isMac = await env.isMacAsync();
 | 
				
			||||||
 | 
					if (isMac) {
 | 
				
			||||||
 | 
					  console.log('Running on macOS');
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### `isLinuxAsync(): Promise<boolean>`
 | 
					#### `isLinuxAsync(): Promise<boolean>`
 | 
				
			||||||
Asynchronously checks if running on Linux.
 | 
					
 | 
				
			||||||
 | 
					Asynchronously checks if running on Linux. Works in Node.js, Deno, and Bun.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					```typescript
 | 
				
			||||||
const isLinux = await smartEnv.isLinuxAsync();
 | 
					const isLinux = await env.isLinuxAsync();
 | 
				
			||||||
if (isLinux) {
 | 
					if (isLinux) {
 | 
				
			||||||
  console.log('Running on Linux');
 | 
					  console.log('Running on Linux');
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Runtime Information
 | 
					#### `isWindowsAsync(): Promise<boolean>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### `nodeVersion: string`
 | 
					Asynchronously checks if running on Windows. Works in Node.js, Deno, and Bun.
 | 
				
			||||||
Returns the Node.js version (only available in Node.js environment).
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					```typescript
 | 
				
			||||||
if (smartEnv.isNode) {
 | 
					const isWindows = await env.isWindowsAsync();
 | 
				
			||||||
  console.log(`Node.js version: ${smartEnv.nodeVersion}`);
 | 
					if (isWindows) {
 | 
				
			||||||
 | 
					  console.log('Running on Windows');
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### `userAgent: string`
 | 
					### Module Loading Methods
 | 
				
			||||||
Returns the browser user agent string (only available in browser environment).
 | 
					
 | 
				
			||||||
 | 
					#### `getSafeModuleFor<T>(target, moduleNameOrUrl, getFunction?): Promise<T | undefined>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**The recommended way to load modules** - supports runtime targeting with flexible options.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Parameters:**
 | 
				
			||||||
 | 
					- `target: TRuntimeTarget | TRuntimeTarget[]` - Runtime(s) to load for
 | 
				
			||||||
 | 
					- `moduleNameOrUrl: string` - Module name (server runtimes) or URL (browser)
 | 
				
			||||||
 | 
					- `getFunction?: () => any` - Function to retrieve module (required for browser)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Returns:** `Promise<T | undefined>` - Loaded module or undefined if runtime doesn't match
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Examples:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					```typescript
 | 
				
			||||||
if (smartEnv.isBrowser) {
 | 
					// Node.js only
 | 
				
			||||||
  console.log(`Browser: ${smartEnv.userAgent}`);
 | 
					const fs = await env.getSafeModuleFor('node', 'fs');
 | 
				
			||||||
}
 | 
					
 | 
				
			||||||
 | 
					// Deno only (note: use 'node:' prefix for Node.js built-ins)
 | 
				
			||||||
 | 
					const path = await env.getSafeModuleFor('deno', 'node:path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// All server runtimes
 | 
				
			||||||
 | 
					const crypto = await env.getSafeModuleFor('server', 'crypto');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Multiple specific runtimes
 | 
				
			||||||
 | 
					const util = await env.getSafeModuleFor(['node', 'bun'], 'util');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Browser
 | 
				
			||||||
 | 
					const lib = await env.getSafeModuleFor(
 | 
				
			||||||
 | 
					  'browser',
 | 
				
			||||||
 | 
					  'https://cdn.example.com/lib.js',
 | 
				
			||||||
 | 
					  () => window.MyLib
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Module Loading
 | 
					#### `getSafeNodeModule<T>(moduleName, runAfterFunc?): Promise<T>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### `getEnvAwareModule(options)`
 | 
					**Legacy method** - Loads modules in server-side runtimes (Node.js, Deno, Bun).
 | 
				
			||||||
Loads a module appropriate for the current environment. In Node.js, it uses dynamic import; in browsers, it loads a script via URL.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					```typescript
 | 
				
			||||||
const module = await smartEnv.getEnvAwareModule({
 | 
					const fs = await env.getSafeNodeModule('fs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// With post-load callback
 | 
				
			||||||
 | 
					const express = await env.getSafeNodeModule('express', async (mod) => {
 | 
				
			||||||
 | 
					  console.log('Express loaded');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `getSafeWebModule(url, getFunction): Promise<any>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Legacy method** - Loads web modules via script tag in browser. Prevents duplicate loading.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					const jQuery = await env.getSafeWebModule(
 | 
				
			||||||
 | 
					  'https://code.jquery.com/jquery-3.6.0.min.js',
 | 
				
			||||||
 | 
					  () => window.jQuery
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `getEnvAwareModule(options): Promise<any>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Legacy method** - Loads environment-appropriate modules.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					const module = await env.getEnvAwareModule({
 | 
				
			||||||
  nodeModuleName: 'node-fetch',
 | 
					  nodeModuleName: 'node-fetch',
 | 
				
			||||||
  webUrlArg: 'https://unpkg.com/whatwg-fetch@3.6.2/dist/fetch.umd.js',
 | 
					  webUrlArg: 'https://unpkg.com/whatwg-fetch@3.6.2/dist/fetch.umd.js',
 | 
				
			||||||
  getFunction: () => window.fetch
 | 
					  getFunction: () => window.fetch
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### `getSafeNodeModule<T>(moduleName, runAfterFunc?)`
 | 
					### Utility Methods
 | 
				
			||||||
Safely loads a Node.js module with error handling. Only works in Node.js environment.
 | 
					
 | 
				
			||||||
 | 
					#### `printEnv(): Promise<void>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Prints environment information to console for debugging.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					```typescript
 | 
				
			||||||
const fs = await smartEnv.getSafeNodeModule('fs');
 | 
					await env.printEnv();
 | 
				
			||||||
if (fs) {
 | 
					// Node.js: "running on NODE" + version
 | 
				
			||||||
  // Use fs module
 | 
					// Deno: "running on DENO" + version
 | 
				
			||||||
}
 | 
					// Bun: "running on BUN" + version
 | 
				
			||||||
 | 
					// Browser: "running on BROWSER" + user agent
 | 
				
			||||||
// With post-load function
 | 
					 | 
				
			||||||
const express = await smartEnv.getSafeNodeModule('express', async (mod) => {
 | 
					 | 
				
			||||||
  console.log('Express loaded successfully');
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### `getSafeWebModule(url, getFunction)`
 | 
					## Real-World Examples
 | 
				
			||||||
Safely loads a web module via script tag. Only works in browser environment. Prevents duplicate loading of the same script.
 | 
					
 | 
				
			||||||
 | 
					### 🌍 Isomorphic Cryptography
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					```typescript
 | 
				
			||||||
const jQuery = await smartEnv.getSafeWebModule(
 | 
					import { Smartenv } from '@push.rocks/smartenv';
 | 
				
			||||||
  'https://code.jquery.com/jquery-3.6.0.min.js',
 | 
					 | 
				
			||||||
  () => window.jQuery
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Debugging
 | 
					const env = new Smartenv();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### `printEnv()`
 | 
					// Load crypto for any server runtime
 | 
				
			||||||
Prints the current environment information to the console for debugging purposes.
 | 
					const crypto = await env.getSafeModuleFor('server', 'crypto');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					if (crypto) {
 | 
				
			||||||
await smartEnv.printEnv();
 | 
					  const hash = crypto.createHash('sha256');
 | 
				
			||||||
// Output in Node.js: "running on NODE" + version
 | 
					  hash.update('hello world');
 | 
				
			||||||
// Output in browser: "running on BROWSER" + user agent
 | 
					  console.log(hash.digest('hex'));
 | 
				
			||||||
```
 | 
					} else if (env.isBrowser) {
 | 
				
			||||||
 | 
					  // Use Web Crypto API
 | 
				
			||||||
## Common Use Cases
 | 
					  const encoder = new TextEncoder();
 | 
				
			||||||
 | 
					  const data = encoder.encode('hello world');
 | 
				
			||||||
### 1. Isomorphic Module Loading
 | 
					  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
 | 
				
			||||||
 | 
					  console.log(Array.from(new Uint8Array(hashBuffer))
 | 
				
			||||||
```typescript
 | 
					    .map(b => b.toString(16).padStart(2, '0'))
 | 
				
			||||||
// Define environment-specific implementations
 | 
					    .join(''));
 | 
				
			||||||
const cryptoModule = await smartEnv.getEnvAwareModule({
 | 
					 | 
				
			||||||
  nodeModuleName: 'crypto',
 | 
					 | 
				
			||||||
  webUrlArg: 'https://unpkg.com/crypto-js@4.1.1/crypto-js.js',
 | 
					 | 
				
			||||||
  getFunction: () => window.CryptoJS
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### 2. Platform-Specific Operations
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```typescript
 | 
					 | 
				
			||||||
if (smartEnv.isNode) {
 | 
					 | 
				
			||||||
  const os = await smartEnv.getSafeNodeModule('os');
 | 
					 | 
				
			||||||
  console.log(`Home directory: ${os.homedir()}`);
 | 
					 | 
				
			||||||
} else {
 | 
					 | 
				
			||||||
  console.log('Browser environment - no filesystem access');
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 3. CI/CD Pipeline Detection
 | 
					### 📁 Cross-Runtime File System
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					```typescript
 | 
				
			||||||
if (smartEnv.isCI) {
 | 
					const env = new Smartenv();
 | 
				
			||||||
  // Run extended tests or different build configuration
 | 
					
 | 
				
			||||||
  console.log('Running in CI - enabling extended test suite');
 | 
					async function readConfig() {
 | 
				
			||||||
} else {
 | 
					  if (env.isNode) {
 | 
				
			||||||
  console.log('Local development environment');
 | 
					    const fs = await env.getSafeModuleFor('node', 'fs/promises');
 | 
				
			||||||
 | 
					    return JSON.parse(await fs.readFile('config.json', 'utf-8'));
 | 
				
			||||||
 | 
					  } else if (env.isDeno) {
 | 
				
			||||||
 | 
					    const content = await Deno.readTextFile('config.json');
 | 
				
			||||||
 | 
					    return JSON.parse(content);
 | 
				
			||||||
 | 
					  } else if (env.isBun) {
 | 
				
			||||||
 | 
					    const file = Bun.file('config.json');
 | 
				
			||||||
 | 
					    return await file.json();
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    // Browser: fetch from server
 | 
				
			||||||
 | 
					    const response = await fetch('/config.json');
 | 
				
			||||||
 | 
					    return response.json();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 4. Dynamic Script Loading in Browser
 | 
					### 🔧 Development vs Production
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					```typescript
 | 
				
			||||||
if (smartEnv.isBrowser) {
 | 
					const env = new Smartenv();
 | 
				
			||||||
  // Load analytics only in browser
 | 
					
 | 
				
			||||||
  await smartEnv.getSafeWebModule(
 | 
					async function setupEnvironment() {
 | 
				
			||||||
    'https://www.google-analytics.com/analytics.js',
 | 
					  // Different behavior in CI
 | 
				
			||||||
    () => window.ga
 | 
					  if (env.isCI) {
 | 
				
			||||||
 | 
					    console.log('CI Environment detected');
 | 
				
			||||||
 | 
					    // Skip interactive prompts, use default values
 | 
				
			||||||
 | 
					    return { mode: 'ci', verbose: true };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Platform-specific paths
 | 
				
			||||||
 | 
					  if (await env.isMacAsync()) {
 | 
				
			||||||
 | 
					    return { configPath: '/Users/username/.config' };
 | 
				
			||||||
 | 
					  } else if (await env.isLinuxAsync()) {
 | 
				
			||||||
 | 
					    return { configPath: '/home/username/.config' };
 | 
				
			||||||
 | 
					  } else if (await env.isWindowsAsync()) {
 | 
				
			||||||
 | 
					    return { configPath: 'C:\\Users\\username\\AppData\\Local' };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 🎨 Conditional Analytics Loading
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					const env = new Smartenv();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function initializeAnalytics() {
 | 
				
			||||||
 | 
					  if (!env.isBrowser) {
 | 
				
			||||||
 | 
					    console.log('Analytics skipped - not in browser');
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Only load analytics in browser
 | 
				
			||||||
 | 
					  const analytics = await env.getSafeModuleFor(
 | 
				
			||||||
 | 
					    'browser',
 | 
				
			||||||
 | 
					    'https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID',
 | 
				
			||||||
 | 
					    () => window.gtag
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (analytics) {
 | 
				
			||||||
 | 
					    analytics('config', 'GA_MEASUREMENT_ID');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 🧪 Runtime-Specific Testing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					const env = new Smartenv();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function runTests() {
 | 
				
			||||||
 | 
					  console.log(`Testing in ${env.runtimeEnv}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Load test utilities for current runtime
 | 
				
			||||||
 | 
					  const testLib = await env.getSafeModuleFor(
 | 
				
			||||||
 | 
					    ['node', 'deno', 'bun'],
 | 
				
			||||||
 | 
					    '@git.zone/tstest'
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (testLib) {
 | 
				
			||||||
 | 
					    // Run server-side tests
 | 
				
			||||||
 | 
					    await runServerTests(testLib);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    // Run browser tests
 | 
				
			||||||
 | 
					    await runBrowserTests();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## TypeScript Support
 | 
					## TypeScript Support
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The package is written in TypeScript and provides full type definitions. The main type export is:
 | 
					smartenv is written in TypeScript and provides complete type definitions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```typescript
 | 
					```typescript
 | 
				
			||||||
export interface IEnvObject {
 | 
					import {
 | 
				
			||||||
  name: string;
 | 
					  Smartenv,
 | 
				
			||||||
  value: string;
 | 
					  TRuntimeType,     // 'node' | 'deno' | 'bun' | 'browser'
 | 
				
			||||||
 | 
					  TRuntimeTarget,   // TRuntimeType | 'server'
 | 
				
			||||||
 | 
					  IEnvObject
 | 
				
			||||||
 | 
					} from '@push.rocks/smartenv';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const env: Smartenv = new Smartenv();
 | 
				
			||||||
 | 
					const runtime: TRuntimeType = env.runtimeEnv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Type-safe module loading
 | 
				
			||||||
 | 
					const fs = await env.getSafeModuleFor<typeof import('fs')>('node', 'fs');
 | 
				
			||||||
 | 
					if (fs) {
 | 
				
			||||||
 | 
					  fs.readFileSync('./file.txt', 'utf-8'); // Full type support
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## How Runtime Detection Works
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					smartenv uses a careful detection order to avoid false positives:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. **Check for Deno** - `globalThis.Deno?.version` (Deno has `process` for compatibility)
 | 
				
			||||||
 | 
					2. **Check for Bun** - `globalThis.Bun?.version` (Bun also has `process`)
 | 
				
			||||||
 | 
					3. **Check for Node.js** - `globalThis.process?.versions?.node` (must be specific)
 | 
				
			||||||
 | 
					4. **Check for Browser** - `globalThis.window && globalThis.document` (fallback)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This order is critical because Deno and Bun provide `process` objects for Node.js compatibility, which would cause false Node.js detection if checked first.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Migration from 4.x to 5.x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Breaking Changes:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. **`runtimeEnv` return type changed:**
 | 
				
			||||||
 | 
					   - **Before:** `'node' | 'browser'`
 | 
				
			||||||
 | 
					   - **After:** `'node' | 'deno' | 'bun' | 'browser'`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. **`isNode` is now more specific:**
 | 
				
			||||||
 | 
					   - **Before:** Returns `true` for Node.js, Deno, and Bun
 | 
				
			||||||
 | 
					   - **After:** Returns `true` only for Node.js
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Migration guide:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					// Before (4.x)
 | 
				
			||||||
 | 
					if (env.isNode) {
 | 
				
			||||||
 | 
					  // This ran in Node.js, Deno, and Bun
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// After (5.x) - Option 1: Check all server runtimes
 | 
				
			||||||
 | 
					if (env.isNode || env.isDeno || env.isBun) {
 | 
				
			||||||
 | 
					  // Works in Node.js, Deno, and Bun
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// After (5.x) - Option 2: Use the new module loading API
 | 
				
			||||||
 | 
					const module = await env.getSafeModuleFor('server', 'path');
 | 
				
			||||||
 | 
					if (module) {
 | 
				
			||||||
 | 
					  // Module loaded successfully in any server runtime
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Performance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- ⚡ **Lightweight** - Minimal overhead with lazy evaluation
 | 
				
			||||||
 | 
					- 🚀 **Fast detection** - Simple boolean checks, no heavy operations
 | 
				
			||||||
 | 
					- 💾 **Cached results** - Detection runs once, results are cached
 | 
				
			||||||
 | 
					- 📦 **Small bundle** - ~5KB minified, tree-shakeable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Browser Compatibility
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tested and working in:
 | 
				
			||||||
 | 
					- ✅ Chrome/Chromium (latest)
 | 
				
			||||||
 | 
					- ✅ Firefox (latest)
 | 
				
			||||||
 | 
					- ✅ Safari (latest)
 | 
				
			||||||
 | 
					- ✅ Edge (latest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Node.js Compatibility
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- ✅ Node.js 18.x
 | 
				
			||||||
 | 
					- ✅ Node.js 20.x (LTS)
 | 
				
			||||||
 | 
					- ✅ Node.js 22.x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Deno Compatibility
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- ✅ Deno 1.40+
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Note:** When using Deno, use the `node:` prefix for Node.js built-in modules:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```typescript
 | 
				
			||||||
 | 
					const path = await env.getSafeModuleFor('deno', 'node:path');
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Bun Compatibility
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- ✅ Bun 1.0+
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## License and Legal Information
 | 
					## License and Legal Information
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
 | 
					This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										81
									
								
								test/test.bun.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								test/test.bun.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
				
			|||||||
 | 
					import { tap, expect } from '@git.zone/tstest/tapbundle';
 | 
				
			||||||
 | 
					import * as smartenv from '../ts/index.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let testEnv: smartenv.Smartenv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should create smartenv instance', async () => {
 | 
				
			||||||
 | 
					  testEnv = new smartenv.Smartenv();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should detect Bun runtime correctly', async () => {
 | 
				
			||||||
 | 
					  expect(testEnv.runtimeEnv).toEqual('bun');
 | 
				
			||||||
 | 
					  expect(testEnv.isBun).toBeTrue();
 | 
				
			||||||
 | 
					  expect(testEnv.isNode).toBeFalse();
 | 
				
			||||||
 | 
					  expect(testEnv.isDeno).toBeFalse();
 | 
				
			||||||
 | 
					  expect(testEnv.isBrowser).toBeFalse();
 | 
				
			||||||
 | 
					  console.log(' Bun runtime detected correctly');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should get Bun version', async () => {
 | 
				
			||||||
 | 
					  const version = testEnv.bunVersion;
 | 
				
			||||||
 | 
					  expect(version).not.toEqual('undefined');
 | 
				
			||||||
 | 
					  expect(typeof version).toEqual('string');
 | 
				
			||||||
 | 
					  console.log('Bun version is ' + version);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should print environment', async () => {
 | 
				
			||||||
 | 
					  testEnv.printEnv();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should load modules for Bun', async () => {
 | 
				
			||||||
 | 
					  const pathModule = await testEnv.getSafeModuleFor('bun', 'path');
 | 
				
			||||||
 | 
					  expect(pathModule).not.toBeUndefined();
 | 
				
			||||||
 | 
					  expect(typeof pathModule.join).toEqual('function');
 | 
				
			||||||
 | 
					  console.log(' Successfully loaded module for Bun');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should load modules for server runtimes', async () => {
 | 
				
			||||||
 | 
					  const pathModule = await testEnv.getSafeModuleFor('server', 'path');
 | 
				
			||||||
 | 
					  expect(pathModule).not.toBeUndefined();
 | 
				
			||||||
 | 
					  expect(typeof pathModule.join).toEqual('function');
 | 
				
			||||||
 | 
					  console.log(' Successfully loaded module with server target');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should load modules for array of runtimes', async () => {
 | 
				
			||||||
 | 
					  const pathModule = await testEnv.getSafeModuleFor(['bun', 'node'], 'path');
 | 
				
			||||||
 | 
					  expect(pathModule).not.toBeUndefined();
 | 
				
			||||||
 | 
					  expect(typeof pathModule.join).toEqual('function');
 | 
				
			||||||
 | 
					  console.log(' Successfully loaded module with array target');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should not load modules for wrong runtime', async () => {
 | 
				
			||||||
 | 
					  const result = await testEnv.getSafeModuleFor('node', 'path');
 | 
				
			||||||
 | 
					  expect(result).toBeUndefined();
 | 
				
			||||||
 | 
					  console.log(' Correctly rejected Node.js-only module in Bun');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should detect OS', async () => {
 | 
				
			||||||
 | 
					  const resultMac = await testEnv.isMacAsync();
 | 
				
			||||||
 | 
					  const resultLinux = await testEnv.isLinuxAsync();
 | 
				
			||||||
 | 
					  const resultWindows = await testEnv.isWindowsAsync();
 | 
				
			||||||
 | 
					  const osModule = await import('os');
 | 
				
			||||||
 | 
					  if (resultMac) {
 | 
				
			||||||
 | 
					    expect(osModule.platform()).toEqual('darwin');
 | 
				
			||||||
 | 
					    console.log('platform is Mac!');
 | 
				
			||||||
 | 
					  } else if (resultLinux) {
 | 
				
			||||||
 | 
					    expect(osModule.platform()).toEqual('linux');
 | 
				
			||||||
 | 
					    console.log('platform is Linux!');
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    expect(osModule.platform()).toEqual('win32');
 | 
				
			||||||
 | 
					    console.log('platform is Windows!');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should detect CI environment if present', async () => {
 | 
				
			||||||
 | 
					  if (process.env.CI) {
 | 
				
			||||||
 | 
					    expect(testEnv.isCI).toBeTrue();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  console.log('CI detection: ' + testEnv.isCI);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.start();
 | 
				
			||||||
							
								
								
									
										58
									
								
								test/test.chrome.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								test/test.chrome.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					import { tap, expect } from '@git.zone/tstest/tapbundle';
 | 
				
			||||||
 | 
					import * as smartenv from '../ts/index.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let testEnv: smartenv.Smartenv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should create smartenv instance', async () => {
 | 
				
			||||||
 | 
					  testEnv = new smartenv.Smartenv();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should detect browser runtime correctly', async () => {
 | 
				
			||||||
 | 
					  expect(testEnv.runtimeEnv).toEqual('browser');
 | 
				
			||||||
 | 
					  expect(testEnv.isBrowser).toBeTrue();
 | 
				
			||||||
 | 
					  expect(testEnv.isNode).toBeFalse();
 | 
				
			||||||
 | 
					  expect(testEnv.isDeno).toBeFalse();
 | 
				
			||||||
 | 
					  expect(testEnv.isBun).toBeFalse();
 | 
				
			||||||
 | 
					  console.log(' Browser runtime detected correctly');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should get user agent', async () => {
 | 
				
			||||||
 | 
					  const userAgent = testEnv.userAgent;
 | 
				
			||||||
 | 
					  expect(userAgent).not.toEqual('undefined');
 | 
				
			||||||
 | 
					  expect(typeof userAgent).toEqual('string');
 | 
				
			||||||
 | 
					  console.log('User agent: ' + userAgent);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should print environment', async () => {
 | 
				
			||||||
 | 
					  testEnv.printEnv();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should not get server runtime versions', async () => {
 | 
				
			||||||
 | 
					  expect(testEnv.nodeVersion).toEqual('undefined');
 | 
				
			||||||
 | 
					  expect(testEnv.denoVersion).toEqual('undefined');
 | 
				
			||||||
 | 
					  expect(testEnv.bunVersion).toEqual('undefined');
 | 
				
			||||||
 | 
					  console.log(' Server runtime versions correctly return undefined in browser');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should not load server modules', async () => {
 | 
				
			||||||
 | 
					  const result = await testEnv.getSafeModuleFor('server', 'path');
 | 
				
			||||||
 | 
					  expect(result).toBeUndefined();
 | 
				
			||||||
 | 
					  console.log(' Correctly rejected server module in browser');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should not detect as CI', async () => {
 | 
				
			||||||
 | 
					  expect(testEnv.isCI).toBeFalse();
 | 
				
			||||||
 | 
					  console.log(' CI detection correctly false in browser');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('OS detection should return false in browser', async () => {
 | 
				
			||||||
 | 
					  const resultMac = await testEnv.isMacAsync();
 | 
				
			||||||
 | 
					  const resultLinux = await testEnv.isLinuxAsync();
 | 
				
			||||||
 | 
					  const resultWindows = await testEnv.isWindowsAsync();
 | 
				
			||||||
 | 
					  expect(resultMac).toBeFalse();
 | 
				
			||||||
 | 
					  expect(resultLinux).toBeFalse();
 | 
				
			||||||
 | 
					  expect(resultWindows).toBeFalse();
 | 
				
			||||||
 | 
					  console.log(' OS detection correctly returns false in browser');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.start();
 | 
				
			||||||
							
								
								
									
										59
									
								
								test/test.deno.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								test/test.deno.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					import { tap, expect } from '@git.zone/tstest/tapbundle';
 | 
				
			||||||
 | 
					import * as smartenv from '../ts/index.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let testEnv: smartenv.Smartenv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should create smartenv instance', async () => {
 | 
				
			||||||
 | 
					  testEnv = new smartenv.Smartenv();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should detect Deno runtime correctly', async () => {
 | 
				
			||||||
 | 
					  expect(testEnv.runtimeEnv).toEqual('deno');
 | 
				
			||||||
 | 
					  expect(testEnv.isDeno).toBeTrue();
 | 
				
			||||||
 | 
					  expect(testEnv.isNode).toBeFalse();
 | 
				
			||||||
 | 
					  expect(testEnv.isBun).toBeFalse();
 | 
				
			||||||
 | 
					  expect(testEnv.isBrowser).toBeFalse();
 | 
				
			||||||
 | 
					  console.log(' Deno runtime detected correctly');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should get Deno version', async () => {
 | 
				
			||||||
 | 
					  const version = testEnv.denoVersion;
 | 
				
			||||||
 | 
					  expect(version).not.toEqual('undefined');
 | 
				
			||||||
 | 
					  expect(typeof version).toEqual('string');
 | 
				
			||||||
 | 
					  console.log('Deno version is ' + version);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should print environment', async () => {
 | 
				
			||||||
 | 
					  testEnv.printEnv();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should load modules for Deno', async () => {
 | 
				
			||||||
 | 
					  // Deno requires 'node:' prefix for Node.js built-in modules
 | 
				
			||||||
 | 
					  const pathModule = await testEnv.getSafeModuleFor('deno', 'node:path');
 | 
				
			||||||
 | 
					  expect(pathModule).not.toBeUndefined();
 | 
				
			||||||
 | 
					  expect(typeof pathModule.join).toEqual('function');
 | 
				
			||||||
 | 
					  console.log(' Successfully loaded module for Deno');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should load modules for server runtimes', async () => {
 | 
				
			||||||
 | 
					  // Deno requires 'node:' prefix for Node.js built-in modules
 | 
				
			||||||
 | 
					  const pathModule = await testEnv.getSafeModuleFor('server', 'node:path');
 | 
				
			||||||
 | 
					  expect(pathModule).not.toBeUndefined();
 | 
				
			||||||
 | 
					  expect(typeof pathModule.join).toEqual('function');
 | 
				
			||||||
 | 
					  console.log(' Successfully loaded module with server target');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should not load modules for wrong runtime', async () => {
 | 
				
			||||||
 | 
					  const result = await testEnv.getSafeModuleFor('node', 'node:path');
 | 
				
			||||||
 | 
					  expect(result).toBeUndefined();
 | 
				
			||||||
 | 
					  console.log(' Correctly rejected Node.js-only module in Deno');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should detect CI environment if present', async () => {
 | 
				
			||||||
 | 
					  // CI detection relies on Node.js process.env, which may not work in Deno
 | 
				
			||||||
 | 
					  // This test documents expected behavior
 | 
				
			||||||
 | 
					  const isCI = testEnv.isCI;
 | 
				
			||||||
 | 
					  console.log('CI detection in Deno: ' + isCI);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.start();
 | 
				
			||||||
							
								
								
									
										81
									
								
								test/test.node.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								test/test.node.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
				
			|||||||
 | 
					import { tap, expect } from '@git.zone/tstest/tapbundle';
 | 
				
			||||||
 | 
					import * as smartenv from '../ts/index.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let testEnv: smartenv.Smartenv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should create smartenv instance', async () => {
 | 
				
			||||||
 | 
					  testEnv = new smartenv.Smartenv();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should detect Node.js runtime correctly', async () => {
 | 
				
			||||||
 | 
					  expect(testEnv.runtimeEnv).toEqual('node');
 | 
				
			||||||
 | 
					  expect(testEnv.isNode).toBeTrue();
 | 
				
			||||||
 | 
					  expect(testEnv.isDeno).toBeFalse();
 | 
				
			||||||
 | 
					  expect(testEnv.isBun).toBeFalse();
 | 
				
			||||||
 | 
					  expect(testEnv.isBrowser).toBeFalse();
 | 
				
			||||||
 | 
					  console.log('✓ Node.js runtime detected correctly (not confused with Deno or Bun)');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should get Node.js version', async () => {
 | 
				
			||||||
 | 
					  const version = testEnv.nodeVersion;
 | 
				
			||||||
 | 
					  expect(version).not.toEqual('undefined');
 | 
				
			||||||
 | 
					  expect(typeof version).toEqual('string');
 | 
				
			||||||
 | 
					  expect(version).toMatch(/^v\d+\.\d+\.\d+/);
 | 
				
			||||||
 | 
					  console.log('Node.js version is ' + version);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should print environment', async () => {
 | 
				
			||||||
 | 
					  testEnv.printEnv();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should load modules for Node.js', async () => {
 | 
				
			||||||
 | 
					  const pathModule = await testEnv.getSafeModuleFor('node', 'path');
 | 
				
			||||||
 | 
					  expect(pathModule).not.toBeUndefined();
 | 
				
			||||||
 | 
					  expect(typeof pathModule.join).toEqual('function');
 | 
				
			||||||
 | 
					  console.log('✓ Successfully loaded module for Node.js');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should load modules for server runtimes', async () => {
 | 
				
			||||||
 | 
					  const pathModule = await testEnv.getSafeModuleFor('server', 'path');
 | 
				
			||||||
 | 
					  expect(pathModule).not.toBeUndefined();
 | 
				
			||||||
 | 
					  expect(typeof pathModule.join).toEqual('function');
 | 
				
			||||||
 | 
					  console.log('✓ Successfully loaded module with server target');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should load modules for array of runtimes', async () => {
 | 
				
			||||||
 | 
					  const pathModule = await testEnv.getSafeModuleFor(['node', 'deno'], 'path');
 | 
				
			||||||
 | 
					  expect(pathModule).not.toBeUndefined();
 | 
				
			||||||
 | 
					  expect(typeof pathModule.join).toEqual('function');
 | 
				
			||||||
 | 
					  console.log('✓ Successfully loaded module with array target');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should not load modules for wrong runtime', async () => {
 | 
				
			||||||
 | 
					  const result = await testEnv.getSafeModuleFor('browser', 'path');
 | 
				
			||||||
 | 
					  expect(result).toBeUndefined();
 | 
				
			||||||
 | 
					  console.log('✓ Correctly rejected browser-only module in Node.js');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should get os', async () => {
 | 
				
			||||||
 | 
					  const resultMac = await testEnv.isMacAsync();
 | 
				
			||||||
 | 
					  const resultLinux = await testEnv.isLinuxAsync();
 | 
				
			||||||
 | 
					  const resultWindows = await testEnv.isWindowsAsync();
 | 
				
			||||||
 | 
					  const osModule = await import('os');
 | 
				
			||||||
 | 
					  if (resultMac) {
 | 
				
			||||||
 | 
					    expect(osModule.platform()).toEqual('darwin');
 | 
				
			||||||
 | 
					    console.log('platform is Mac!');
 | 
				
			||||||
 | 
					  } else if (resultLinux) {
 | 
				
			||||||
 | 
					    expect(osModule.platform()).toEqual('linux');
 | 
				
			||||||
 | 
					    console.log('platform is Linux!');
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    expect(osModule.platform()).toEqual('win32');
 | 
				
			||||||
 | 
					    console.log('platform is Windows!');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.test('should state wether we are in CI', async () => {
 | 
				
			||||||
 | 
					  if (process.env.CI) {
 | 
				
			||||||
 | 
					    expect(testEnv.isCI).toBeTrue();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tap.start();
 | 
				
			||||||
							
								
								
									
										37
									
								
								test/test.ts
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								test/test.ts
									
									
									
									
									
								
							@@ -1,37 +0,0 @@
 | 
				
			|||||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
 | 
					 | 
				
			||||||
import * as smartenv from '../ts/index.js';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let testEnv: smartenv.Smartenv;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
tap.test('should print env', async () => {
 | 
					 | 
				
			||||||
  testEnv = new smartenv.Smartenv();
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
tap.test('should print a overview to console', async () => {
 | 
					 | 
				
			||||||
  testEnv.printEnv();
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
tap.test('should get os', async () => {
 | 
					 | 
				
			||||||
  const resultMac = await testEnv.isMacAsync();
 | 
					 | 
				
			||||||
  const resultLinux = await testEnv.isLinuxAsync();
 | 
					 | 
				
			||||||
  const resultWindows = await testEnv.isWindowsAsync();
 | 
					 | 
				
			||||||
  const osModule = await import('os');
 | 
					 | 
				
			||||||
  if (resultMac) {
 | 
					 | 
				
			||||||
    expect(osModule.platform()).toEqual('darwin');
 | 
					 | 
				
			||||||
    console.log('platform is Mac!');
 | 
					 | 
				
			||||||
  } else if (resultLinux) {
 | 
					 | 
				
			||||||
    expect(osModule.platform()).toEqual('linux');
 | 
					 | 
				
			||||||
    console.log('platform is Linux!');
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    expect(osModule.platform()).toEqual('win32');
 | 
					 | 
				
			||||||
    console.log('platform is Windows!');
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
tap.test('should state wether we are in CI', async () => {
 | 
					 | 
				
			||||||
  if (process.env.CI) {
 | 
					 | 
				
			||||||
    expect(testEnv.isCI).toBeTrue();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
tap.start();
 | 
					 | 
				
			||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * autocreated commitinfo by @pushrocks/commitinfo
 | 
					 * autocreated commitinfo by @push.rocks/commitinfo
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export const commitinfo = {
 | 
					export const commitinfo = {
 | 
				
			||||||
  name: '@push.rocks/smartenv',
 | 
					  name: '@push.rocks/smartenv',
 | 
				
			||||||
  version: '5.0.12',
 | 
					  version: '6.0.0',
 | 
				
			||||||
  description: 'store things about your environment and let them travel across modules'
 | 
					  description: 'A module for storing and accessing environment details across different platforms.'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,15 @@
 | 
				
			|||||||
export let defaultme = null;
 | 
					export let defaultme = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Runtime type representing the detected JavaScript runtime environment
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type TRuntimeType = 'node' | 'deno' | 'bun' | 'browser';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Runtime target for module loading - can be a specific runtime or 'server' for all server-side runtimes
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type TRuntimeTarget = TRuntimeType | 'server';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
declare global {
 | 
					declare global {
 | 
				
			||||||
  namespace NodeJS {
 | 
					  namespace NodeJS {
 | 
				
			||||||
    interface Global {
 | 
					    interface Global {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,8 +31,8 @@ export class Smartenv {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public async getSafeNodeModule<T = any>(moduleNameArg: string, runAfterFunc?: (moduleArg: T) => Promise<any>): Promise<T> {
 | 
					  public async getSafeNodeModule<T = any>(moduleNameArg: string, runAfterFunc?: (moduleArg: T) => Promise<any>): Promise<T> {
 | 
				
			||||||
    if (!this.isNode) {
 | 
					    if (!this.isNode && !this.isDeno && !this.isBun) {
 | 
				
			||||||
      console.error(`You tried to load a node module in a wrong context: ${moduleNameArg}. This does not throw.`);
 | 
					      console.error(`You tried to load a server module in a wrong context: ${moduleNameArg}. This does not throw.`);
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    // tslint:disable-next-line: function-constructor
 | 
					    // tslint:disable-next-line: function-constructor
 | 
				
			||||||
@@ -72,16 +72,49 @@ export class Smartenv {
 | 
				
			|||||||
    return getFunctionArg();
 | 
					    return getFunctionArg();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public get runtimeEnv() {
 | 
					  public get runtimeEnv(): interfaces.TRuntimeType {
 | 
				
			||||||
    if (typeof process !== 'undefined') {
 | 
					    // Check Deno first (most distinctive)
 | 
				
			||||||
 | 
					    if (typeof globalThis.Deno !== 'undefined' &&
 | 
				
			||||||
 | 
					        typeof (globalThis as any).Deno?.version !== 'undefined') {
 | 
				
			||||||
 | 
					      return 'deno';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check Bun second (most distinctive)
 | 
				
			||||||
 | 
					    if (typeof globalThis.Bun !== 'undefined' &&
 | 
				
			||||||
 | 
					        typeof (globalThis as any).Bun?.version !== 'undefined') {
 | 
				
			||||||
 | 
					      return 'bun';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check Node.js (be explicit about versions to avoid Deno/Bun false positives)
 | 
				
			||||||
 | 
					    if (typeof globalThis.process !== 'undefined' &&
 | 
				
			||||||
 | 
					        typeof (globalThis as any).process?.versions?.node !== 'undefined') {
 | 
				
			||||||
      return 'node';
 | 
					      return 'node';
 | 
				
			||||||
    } else {
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check Browser (default fallback)
 | 
				
			||||||
 | 
					    if (typeof globalThis.window !== 'undefined' &&
 | 
				
			||||||
 | 
					        typeof (globalThis as any).document !== 'undefined') {
 | 
				
			||||||
      return 'browser';
 | 
					      return 'browser';
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Safe fallback
 | 
				
			||||||
 | 
					    return 'browser';
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public get isBrowser(): boolean {
 | 
					  public get isBrowser(): boolean {
 | 
				
			||||||
    return !this.isNode;
 | 
					    return this.runtimeEnv === 'browser';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public get isNode(): boolean {
 | 
				
			||||||
 | 
					    return this.runtimeEnv === 'node';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public get isDeno(): boolean {
 | 
				
			||||||
 | 
					    return this.runtimeEnv === 'deno';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public get isBun(): boolean {
 | 
				
			||||||
 | 
					    return this.runtimeEnv === 'bun';
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public get userAgent(): string {
 | 
					  public get userAgent(): string {
 | 
				
			||||||
@@ -93,12 +126,77 @@ export class Smartenv {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public get isNode(): boolean {
 | 
					  public get nodeVersion(): string {
 | 
				
			||||||
    return this.runtimeEnv === 'node';
 | 
					    if (this.isNode) {
 | 
				
			||||||
 | 
					      return process.version;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 'undefined';
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public get nodeVersion(): string {
 | 
					  public get denoVersion(): string {
 | 
				
			||||||
    return process.version;
 | 
					    if (this.isDeno) {
 | 
				
			||||||
 | 
					      return (globalThis as any).Deno.version.deno;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 'undefined';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public get bunVersion(): string {
 | 
				
			||||||
 | 
					    if (this.isBun) {
 | 
				
			||||||
 | 
					      return (globalThis as any).Bun.version;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 'undefined';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Load a module only if the current runtime matches the target runtime(s)
 | 
				
			||||||
 | 
					   * @param target - Single runtime, array of runtimes, or 'server' for all server-side runtimes
 | 
				
			||||||
 | 
					   * @param moduleNameOrUrl - Module name (for Node/Deno/Bun) or URL (for browser)
 | 
				
			||||||
 | 
					   * @param getFunction - Optional function to retrieve the module in browser context
 | 
				
			||||||
 | 
					   * @returns The loaded module or undefined if runtime doesn't match
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public async getSafeModuleFor<T = any>(
 | 
				
			||||||
 | 
					    target: interfaces.TRuntimeTarget | interfaces.TRuntimeTarget[],
 | 
				
			||||||
 | 
					    moduleNameOrUrl: string,
 | 
				
			||||||
 | 
					    getFunction?: () => any
 | 
				
			||||||
 | 
					  ): Promise<T | undefined> {
 | 
				
			||||||
 | 
					    // Normalize target to array
 | 
				
			||||||
 | 
					    let targetRuntimes: interfaces.TRuntimeType[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (Array.isArray(target)) {
 | 
				
			||||||
 | 
					      // Expand 'server' if present in array
 | 
				
			||||||
 | 
					      targetRuntimes = target.flatMap(t =>
 | 
				
			||||||
 | 
					        t === 'server' ? ['node', 'deno', 'bun'] as interfaces.TRuntimeType[] : [t as interfaces.TRuntimeType]
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    } else if (target === 'server') {
 | 
				
			||||||
 | 
					      targetRuntimes = ['node', 'deno', 'bun'];
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      targetRuntimes = [target];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check if current runtime matches any target
 | 
				
			||||||
 | 
					    if (!targetRuntimes.includes(this.runtimeEnv)) {
 | 
				
			||||||
 | 
					      console.warn(
 | 
				
			||||||
 | 
					        `Module "${moduleNameOrUrl}" requested for runtime(s) [${targetRuntimes.join(', ')}] ` +
 | 
				
			||||||
 | 
					        `but current runtime is "${this.runtimeEnv}". Skipping load.`
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      return undefined;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Load based on current runtime
 | 
				
			||||||
 | 
					    if (this.isNode || this.isDeno || this.isBun) {
 | 
				
			||||||
 | 
					      // Server-side runtimes use dynamic import
 | 
				
			||||||
 | 
					      const moduleResult = await this.getSafeNodeModule<T>(moduleNameOrUrl);
 | 
				
			||||||
 | 
					      return moduleResult;
 | 
				
			||||||
 | 
					    } else if (this.isBrowser) {
 | 
				
			||||||
 | 
					      if (!getFunction) {
 | 
				
			||||||
 | 
					        console.error(`Browser module load requires getFunction parameter for "${moduleNameOrUrl}"`);
 | 
				
			||||||
 | 
					        return undefined;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const moduleResult = await this.getSafeWebModule(moduleNameOrUrl, getFunction);
 | 
				
			||||||
 | 
					      return moduleResult as T;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return undefined;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public get isCI(): boolean {
 | 
					  public get isCI(): boolean {
 | 
				
			||||||
@@ -147,6 +245,12 @@ export class Smartenv {
 | 
				
			|||||||
    if (this.isNode) {
 | 
					    if (this.isNode) {
 | 
				
			||||||
      console.log('running on NODE');
 | 
					      console.log('running on NODE');
 | 
				
			||||||
      console.log('node version is ' + this.nodeVersion);
 | 
					      console.log('node version is ' + this.nodeVersion);
 | 
				
			||||||
 | 
					    } else if (this.isDeno) {
 | 
				
			||||||
 | 
					      console.log('running on DENO');
 | 
				
			||||||
 | 
					      console.log('deno version is ' + this.denoVersion);
 | 
				
			||||||
 | 
					    } else if (this.isBun) {
 | 
				
			||||||
 | 
					      console.log('running on BUN');
 | 
				
			||||||
 | 
					      console.log('bun version is ' + this.bunVersion);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      console.log('running on BROWSER');
 | 
					      console.log('running on BROWSER');
 | 
				
			||||||
      console.log('browser is ' + this.userAgent);
 | 
					      console.log('browser is ' + this.userAgent);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user