1.2.1 β€’ Published 7 months ago

runtime-detector v1.2.1

Weekly downloads
-
License
MIT
Repository
github
Last release
7 months ago

Runtime Detector

npm version License: MIT Bundle Size

A lightweight, type-safe runtime environment detector for JavaScript/TypeScript applications. Easily detect and handle code execution in Bun, Node.js, Deno, and Browser environments.

πŸš€ Key Features

  • Environment Callbacks: Execute code through environment-specific callback functions
  • Return Values: Callback functions can return values for further processing
  • Zero Dependencies: No external dependencies
  • TypeScript Ready: Full TypeScript support with type definitions included
  • Lightweight: Only ~7KB minified
  • Universal Detection: Supports Bun, Node.js, Deno, and Browser environments
  • Flexible API: Both synchronous and asynchronous operations
  • Type Safety: Environment-specific code execution with TypeScript type checking
  • Tree-Shakeable: Import only what you need
  • Dual Package: Supports both ESM (MJS) and CommonJS (CJS)

πŸ“¦ Installation

# Using npm
npm install runtime-detector

# Using yarn
yarn add runtime-detector

# Using pnpm
pnpm add runtime-detector

# Using bun
bun add runtime-detector

πŸ“ Module Support

runtime-detector supports both ESM (ECMAScript Modules) and CommonJS formats.

// ESM (MJS)
import { currentEnv, isNodejs } from "runtime-detector";

// CommonJS (CJS)
const { currentEnv, isNodejs } = require("runtime-detector");

🎯 Quick Start

Basic Environment Detection

import { currentEnv, isNodejs, isBrowser } from "runtime-detector";

// Configuration setup example
function setupConfig() {
  const { name, version, browserName } = currentEnv;
  
  // Set environment-specific logging levels
  const config = {
    logLevel: isNodejs ? 'verbose' : 'error',
    maxRetries: isBrowser ? 3 : 5,
    timeout: isBrowser ? 5000 : 10000,
    features: {
      cache: isNodejs || browserName === 'Chrome',
      analytics: isBrowser && browserName !== 'Firefox',
      ssr: !isBrowser
    }
  };

  return config;
}

Environment-Specific Code Execution

import { onNodejs, onBrowser, onBun, onDeno } from "runtime-detector";

// File handling across different environments
function saveData(content: string) {
  // Node.js: Use fs with proper error handling
  onNodejs((env) => {
    const fs = require('fs').promises;
    return fs.writeFile('data.json', content)
      .catch(err => console.error(`Failed to write file in Node.js ${env.version}:`, err));
  });

  // Browser: Use localStorage with size check
  onBrowser((env) => {
    try {
      const maxSize = 5 * 1024 * 1024; // 5MB
      if (content.length > maxSize) {
        throw new Error('Content too large for localStorage');
      }
      localStorage.setItem('data', content);
      console.log(`Data saved in ${env.browserName}`);
    } catch (err) {
      console.error('Storage failed:', err);
    }
  });

  // Bun: Use fast native file API
  onBun((env) => {
    try {
      Bun.write('data.json', content);
      console.log(`File written using Bun ${env.version}`);
    } catch (err) {
      console.error('Bun write failed:', err);
    }
  });

  // Deno: Use native APIs with permissions
  onDeno((env) => {
    try {
      Deno.writeTextFileSync('data.json', content);
      console.log(`File written in Deno ${env.version}`);
    } catch (err) {
      console.error('Deno write failed:', err);
    }
  });
}

Async Operations with Error Handling

import { onNodejsAsync, onBrowserAsync } from "runtime-detector";

// API client with environment-specific optimizations
class APIClient {
  async fetchData(endpoint: string) {
    // Browser: Use native fetch with timeout
    const browserData = await onBrowserAsync(async (env) => {
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), 5000);
      
      try {
        const response = await fetch(endpoint, {
          headers: {
            'User-Agent': `WebApp/${env.browserName}`,
            'Accept': 'application/json'
          },
          signal: controller.signal
        });
        
        if (!response.ok) throw new Error(`HTTP ${response.status}`);
        return await response.json();
      } catch (err) {
        console.error(`Browser fetch failed:`, err);
        throw err;
      } finally {
        clearTimeout(timeoutId);
      }
    });

    // Node.js: Use axios with retries
    const nodeData = await onNodejsAsync(async (env) => {
      const axios = require('axios');
      let retries = 3;
      
      while (retries > 0) {
        try {
          const response = await axios.get(endpoint, {
            headers: {
              'User-Agent': `NodeApp/${env.version}`,
              'Accept': 'application/json'
            },
            timeout: 5000
          });
          return response.data;
        } catch (err) {
          retries--;
          if (retries === 0) throw err;
          await new Promise(resolve => setTimeout(resolve, 1000));
        }
      }
    });

    return browserData || nodeData;
  }
}

Feature Detection and Optimization

import { onNotNodejs, onNotBrowser } from "runtime-detector";

// Cache system optimization example
function setupCache(data: any) {
  // Use Redis in server environments
  onNotBrowser(async (env) => {
    const Redis = require('redis');
    const client = Redis.createClient();
    
    try {
      await client.connect();
      await client.set('app:cache', JSON.stringify(data));
      console.log(`Redis cache setup in ${env.name}`);
    } catch (err) {
      console.error(`Cache setup failed in ${env.name}:`, err);
      // Fallback to in-memory cache
      global.__cache = data;
    }
  });

  // Use IndexedDB in browser
  onBrowser((env) => {
    const request = indexedDB.open('appCache', 1);
    
    request.onerror = () => {
      console.error(`IndexedDB failed in ${env.browserName}`);
      // Fallback to sessionStorage
      sessionStorage.setItem('cache', JSON.stringify(data));
    };

    request.onsuccess = (event: any) => {
      const db = event.target.result;
      const tx = db.transaction('cache', 'readwrite');
      tx.objectStore('cache').put(data, 'appData');
    };
  });
}

πŸ“š API Reference

Environment Information

  • currentEnv: Current environment details
    • name: Runtime name (e.g., "Node.js", "Bun")
    • version: Runtime version
    • browserName: Browser name (if applicable)

Environment Checks

import {
  isBrowser,  // true in browser environments
  isNodejs,   // true in Node.js
  isBun,      // true in Bun
  isDeno      // true in Deno
} from "runtime-detector";

Synchronous Execution APIs

FunctionDescription
onBrowser(callback)Execute in browser
onNodejs(callback)Execute in Node.js
onBun(callback)Execute in Bun
onDeno(callback)Execute in Deno
onNotBrowser(callback)Execute in non-browser
onNotNodejs(callback)Execute in non-Node.js
onNotBun(callback)Execute in non-Bun
onNotDeno(callback)Execute in non-Deno

Asynchronous Execution APIs

FunctionDescription
onBrowserAsync(callback)Async execute in browser
onNodejsAsync(callback)Async execute in Node.js
onBunAsync(callback)Async execute in Bun
onDenoAsync(callback)Async execute in Deno
onNotBrowserAsync(callback)Async execute in non-browser
onNotNodejsAsync(callback)Async execute in non-Node.js
onNotBunAsync(callback)Async execute in non-Bun
onNotDenoAsync(callback)Async execute in non-Deno

πŸ“‹ Release Notes

1.2.0

  • πŸ› Bug Fix: Fixed critical issue where on* functions could potentially execute in incorrect environments
    • Previously, code within environment-specific functions could sometimes run in unintended environments
    • Now strictly enforces environment checks before executing any code
    • Affects all environment-specific functions (onNodejs, onBrowser, onBun, onDeno, etc.)

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

πŸ“„ License

MIT License - feel free to use this project in your applications.


Runtime Detector (ν•œκ΅­μ–΄)

npm version License: MIT Bundle Size

JavaScript/TypeScript μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μœ„ν•œ κ²½λŸ‰ λŸ°νƒ€μž„ ν™˜κ²½ 감지 λΌμ΄λΈŒλŸ¬λ¦¬μž…λ‹ˆλ‹€. Bun, Node.js, Deno, λΈŒλΌμš°μ € ν™˜κ²½μ„ μ‰½κ²Œ κ°μ§€ν•˜κ³  μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

πŸš€ μ£Όμš” κΈ°λŠ₯

  • ν™˜κ²½λ³„ 콜백: ν™˜κ²½λ³„ 콜백 ν•¨μˆ˜λ₯Ό ν†΅ν•œ μ½”λ“œ μ‹€ν–‰ 지원
  • λ°˜ν™˜κ°’ 지원: 콜백 ν•¨μˆ˜μ—μ„œ 값을 λ°˜ν™˜ν•˜μ—¬ μΆ”κ°€ 처리 κ°€λŠ₯
  • μ˜μ‘΄μ„± μ—†μŒ: μ™ΈλΆ€ μ˜μ‘΄μ„±μ΄ μ—†μŒ
  • TypeScript 지원: νƒ€μž… μ •μ˜κ°€ ν¬ν•¨λœ μ™„λ²½ν•œ TypeScript 지원
  • κ²½λŸ‰ν™”: μ•½ 7KB (μ••μΆ• μ‹œ)
  • λ‹€μ–‘ν•œ ν™˜κ²½ 감지: Bun, Node.js, Deno, λΈŒλΌμš°μ € ν™˜κ²½ 지원
  • μœ μ—°ν•œ API: 동기 및 비동기 μž‘μ—… λͺ¨λ‘ 지원
  • νƒ€μž… μ•ˆμ „μ„±: TypeScript νƒ€μž… 체크와 ν•¨κ»˜ ν™˜κ²½λ³„ μ½”λ“œ μ‹€ν–‰
  • 트리 쉐이킹: ν•„μš”ν•œ κΈ°λŠ₯만 μž„ν¬νŠΈ κ°€λŠ₯
  • λ“€μ–Ό νŒ¨ν‚€μ§€: ESM(MJS)와 CommonJS(CJS) λͺ¨λ‘ 지원

πŸ“¦ μ„€μΉ˜

# npm μ‚¬μš©
npm install runtime-detector

# yarn μ‚¬μš©
yarn add runtime-detector

# pnpm μ‚¬μš©
pnpm add runtime-detector

# bun μ‚¬μš©
bun add runtime-detector

πŸ“ λͺ¨λ“ˆ 지원

runtime-detectorλŠ” ESM(ECMAScript Modules)κ³Ό CommonJS ν˜•μ‹μ„ λͺ¨λ‘ μ§€μ›ν•©λ‹ˆλ‹€.

// ESM (MJS)
import { currentEnv, isNodejs } from "runtime-detector";

// CommonJS (CJS)
const { currentEnv, isNodejs } = require("runtime-detector");

🎯 μ‹œμž‘ν•˜κΈ°

κΈ°λ³Έ ν™˜κ²½ 감지

import { currentEnv, isNodejs, isBrowser } from "runtime-detector";

// ν™˜κ²½λ³„ μ„€μ • ꡬ성 예제
function setupConfig() {
  const { name, version, browserName } = currentEnv;
  
  // ν™˜κ²½λ³„ λ‘œκΉ… 레벨 및 μ„€μ • μ§€μ •
  const config = {
    logLevel: isNodejs ? 'verbose' : 'error',
    maxRetries: isBrowser ? 3 : 5,
    timeout: isBrowser ? 5000 : 10000,
    features: {
      cache: isNodejs || browserName === 'Chrome',
      analytics: isBrowser && browserName !== 'Firefox',
      ssr: !isBrowser
    }
  };

  return config;
}

ν™˜κ²½λ³„ μ½”λ“œ μ‹€ν–‰

import { onNodejs, onBrowser, onBun, onDeno } from "runtime-detector";

// λ‹€μ–‘ν•œ ν™˜κ²½μ—μ„œμ˜ 파일 처리
function saveData(content: string) {
  // Node.js: fs λͺ¨λ“ˆ μ‚¬μš© 및 였λ₯˜ 처리
  onNodejs((env) => {
    const fs = require('fs').promises;
    return fs.writeFile('data.json', content)
      .catch(err => console.error(`Node.js ${env.version}μ—μ„œ 파일 μ“°κΈ° μ‹€νŒ¨:`, err));
  });

  // λΈŒλΌμš°μ €: localStorage μ‚¬μš© 및 μš©λŸ‰ 확인
  onBrowser((env) => {
    try {
      const maxSize = 5 * 1024 * 1024; // 5MB
      if (content.length > maxSize) {
        throw new Error('localStorage μš©λŸ‰ 초과');
      }
      localStorage.setItem('data', content);
      console.log(`${env.browserName}μ—μ„œ 데이터 μ €μž₯ μ™„λ£Œ`);
    } catch (err) {
      console.error('μ €μž₯ μ‹€νŒ¨:', err);
    }
  });

  // Bun: λ„€μ΄ν‹°λΈŒ 파일 API ν™œμš©
  onBun((env) => {
    try {
      Bun.write('data.json', content);
      console.log(`Bun ${env.version}μ—μ„œ 파일 μž‘μ„± μ™„λ£Œ`);
    } catch (err) {
      console.error('Bun μ“°κΈ° μ‹€νŒ¨:', err);
    }
  });

  // Deno: κΆŒν•œ 관리와 ν•¨κ»˜ λ„€μ΄ν‹°λΈŒ API μ‚¬μš©
  onDeno((env) => {
    try {
      Deno.writeTextFileSync('data.json', content);
      console.log(`Deno ${env.version}μ—μ„œ 파일 μž‘μ„± μ™„λ£Œ`);
    } catch (err) {
      console.error('Deno μ“°κΈ° μ‹€νŒ¨:', err);
    }
  });

였λ₯˜ 처리λ₯Ό ν¬ν•¨ν•œ 비동기 μž‘μ—…

import { onNodejsAsync, onBrowserAsync } from "runtime-detector";

// ν™˜κ²½λ³„ μ΅œμ ν™”λœ API ν΄λΌμ΄μ–ΈνŠΈ
class APIClient {
  async fetchData(endpoint: string) {
    // λΈŒλΌμš°μ €: νƒ€μž„μ•„μ›ƒμ΄ μžˆλŠ” λ„€μ΄ν‹°λΈŒ fetch μ‚¬μš©
    const browserData = await onBrowserAsync(async (env) => {
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), 5000);
      
      try {
        const response = await fetch(endpoint, {
          headers: {
            'User-Agent': `WebApp/${env.browserName}`,
            'Accept': 'application/json'
          },
          signal: controller.signal
        });
        
        if (!response.ok) throw new Error(`HTTP ${response.status}`);
        return await response.json();
      } catch (err) {
        console.error(`λΈŒλΌμš°μ € fetch μ‹€νŒ¨:`, err);
        throw err;
      } finally {
        clearTimeout(timeoutId);
      }
    });

    // Node.js: axios μ‚¬μš© 및 μž¬μ‹œλ„ 둜직 κ΅¬ν˜„
    const nodeData = await onNodejsAsync(async (env) => {
      const axios = require('axios');
      let retries = 3;
      
      while (retries > 0) {
        try {
          const response = await axios.get(endpoint, {
            headers: {
              'User-Agent': `NodeApp/${env.version}`,
              'Accept': 'application/json'
            },
            timeout: 5000
          });
          return response.data;
        } catch (err) {
          retries--;
          if (retries === 0) throw err;
          await new Promise(resolve => setTimeout(resolve, 1000));
        }
      }
    });

    return browserData || nodeData;
  }
}

κΈ°λŠ₯ 감지 및 μ΅œμ ν™”

import { onNotNodejs, onNotBrowser } from "runtime-detector";

// μΊμ‹œ μ‹œμŠ€ν…œ μ΅œμ ν™” 예제
function setupCache(data: any) {
  // μ„œλ²„ ν™˜κ²½μ—μ„œ Redis μ‚¬μš©
  onNotBrowser(async (env) => {
    const Redis = require('redis');
    const client = Redis.createClient();
    
    try {
      await client.connect();
      await client.set('app:cache', JSON.stringify(data));
      console.log(`Redis μΊμ‹œκ°€ ${env.name}에 섀정됨`);
    } catch (err) {
      console.error(`${env.name}μ—μ„œ μΊμ‹œ μ„€μ • μ‹€νŒ¨:`, err);
      // λ©”λͺ¨λ¦¬ μΊμ‹œλ‘œ λŒ€μ²΄
      global.__cache = data;
    }
  });

  // λΈŒλΌμš°μ €μ—μ„œ IndexedDB μ‚¬μš©
  onBrowser((env) => {
    const request = indexedDB.open('appCache', 1);
    
    request.onerror = () => {
      console.error(`${env.browserName}μ—μ„œ IndexedDB μ‹€νŒ¨`);
      // sessionStorage둜 λŒ€μ²΄
      sessionStorage.setItem('cache', JSON.stringify(data));
    };

    request.onsuccess = (event: any) => {
      const db = event.target.result;
      const tx = db.transaction('cache', 'readwrite');
      tx.objectStore('cache').put(data, 'appData');
    };
  });
}

πŸ“š API 레퍼런슀

ν™˜κ²½ 정보

  • currentEnv: ν˜„μž¬ ν™˜κ²½ 상세 정보
    • name: λŸ°νƒ€μž„ 이름 (예: "Node.js", "Bun")
    • version: λŸ°νƒ€μž„ 버전
    • browserName: λΈŒλΌμš°μ € 이름 (ν•΄λ‹Ήλ˜λŠ” 경우)

ν™˜κ²½ 확인

import {
  isBrowser,  // λΈŒλΌμš°μ € ν™˜κ²½μ—μ„œ true
  isNodejs,   // Node.jsμ—μ„œ true
  isBun,      // Bunμ—μ„œ true
  isDeno      // Denoμ—μ„œ true
} from "runtime-detector";

동기 μ‹€ν–‰ API

ν•¨μˆ˜μ„€λͺ…
onBrowser(callback)λΈŒλΌμš°μ €μ—μ„œ μ‹€ν–‰
onNodejs(callback)Node.jsμ—μ„œ μ‹€ν–‰
onBun(callback)Bunμ—μ„œ μ‹€ν–‰
onDeno(callback)Denoμ—μ„œ μ‹€ν–‰
onNotBrowser(callback)λΈŒλΌμš°μ €κ°€ μ•„λ‹Œ ν™˜κ²½μ—μ„œ μ‹€ν–‰
onNotNodejs(callback)Node.jsκ°€ μ•„λ‹Œ ν™˜κ²½μ—μ„œ μ‹€ν–‰
onNotBun(callback)Bun이 μ•„λ‹Œ ν™˜κ²½μ—μ„œ μ‹€ν–‰
onNotDeno(callback)Denoκ°€ μ•„λ‹Œ ν™˜κ²½μ—μ„œ μ‹€ν–‰

비동기 μ‹€ν–‰ API

ν•¨μˆ˜μ„€λͺ…
onBrowserAsync(callback)λΈŒλΌμš°μ €μ—μ„œ 비동기 μ‹€ν–‰
onNodejsAsync(callback)Node.jsμ—μ„œ 비동기 μ‹€ν–‰
onBunAsync(callback)Bunμ—μ„œ 비동기 μ‹€ν–‰
onDenoAsync(callback)Denoμ—μ„œ 비동기 μ‹€ν–‰
onNotBrowserAsync(callback)λΈŒλΌμš°μ €κ°€ μ•„λ‹Œ ν™˜κ²½μ—μ„œ 비동기 μ‹€ν–‰
onNotNodejsAsync(callback)Node.jsκ°€ μ•„λ‹Œ ν™˜κ²½μ—μ„œ 비동기 μ‹€ν–‰
onNotBunAsync(callback)Bun이 μ•„λ‹Œ ν™˜κ²½μ—μ„œ 비동기 μ‹€ν–‰
onNotDenoAsync(callback)Denoκ°€ μ•„λ‹Œ ν™˜κ²½μ—μ„œ 비동기 μ‹€ν–‰

πŸ“‹ 릴리슀 λ…ΈνŠΈ

1.2.0

  • πŸ› 버그 μˆ˜μ •: on* ν•¨μˆ˜λ“€μ΄ 잘λͺ»λœ ν™˜κ²½μ—μ„œ 싀행될 수 μžˆλŠ” μ€‘μš”ν•œ 문제 ν•΄κ²°
    • μ΄μ „μ—λŠ” ν™˜κ²½λ³„ ν•¨μˆ˜ λ‚΄μ˜ μ½”λ“œκ°€ μ˜λ„ν•˜μ§€ μ•Šμ€ ν™˜κ²½μ—μ„œ 싀행될 수 μžˆμ—ˆμŒ
    • 이제 μ½”λ“œ μ‹€ν–‰ 전에 ν™˜κ²½ 검사λ₯Ό μ—„κ²©ν•˜κ²Œ μˆ˜ν–‰
    • λͺ¨λ“  ν™˜κ²½λ³„ ν•¨μˆ˜μ— 적용 (onNodejs, onBrowser, onBun, onDeno λ“±)

🀝 κΈ°μ—¬ν•˜κΈ°

κΈ°μ—¬λŠ” μ–Έμ œλ‚˜ ν™˜μ˜ν•©λ‹ˆλ‹€! Pull Requestλ₯Ό 자유둭게 μ œμΆœν•΄ μ£Όμ„Έμš”.

πŸ“„ λΌμ΄μ„ μŠ€

MIT λΌμ΄μ„ μŠ€ - μ—¬λŸ¬λΆ„μ˜ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ— 자유둭게 μ‚¬μš©ν•˜μ‹€ 수 μžˆμŠ΅λ‹ˆλ‹€.

1.2.1

7 months ago

1.2.0

7 months ago

1.0.2

7 months ago

1.0.1

7 months ago

1.0.0

7 months ago