Skip to content

Developer API

Wesley Yan S. B. edited this page Jan 9, 2026 · 1 revision

ByHun Developer API Documentation

Table of Contents


Introduction

The Byhun Developer API allows web-based apps to interact with the file system and system information in a secure, sandboxed environment. All file operations are restricted to an isolated directory specific to your app, ensuring security and preventing malicious access to the user's system.

Features

  • ✅ Secure file operations (read, write, delete, move)
  • ✅ File listing and information
  • ✅ System information access
  • ✅ Complete sandbox isolation
  • ✅ Async/await Promise-based API

Requirements

  • Developer API must be enabled in Byhun settings (disabled by default)
  • Your app must be loaded in Byhun WebView
  • All file operations are automatically restricted to your app's sandbox

Getting Started

1. Enable Developer API

Before using the API, users must enable it in Byhun settings:

  1. Open Byhun app
  2. Go to Settings
  3. Scroll to Developer API section
  4. Toggle Enable Developer API ON
  5. Save settings

⚠️ Warning: Users should only enable this if they trust your app.

2. Check API Availability

Always check if the API is available and enabled before using it:

// Check if API is available
if (typeof window.byhunAPI === 'undefined') {
  console.error('Byhun API is not available');
  alert('Please enable Developer API in Byhun settings');
  return;
}

// Check if API is enabled
if (!window.byhunAPI.enabled) {
  console.error('Byhun API is disabled');
  alert('Please enable Developer API in Byhun settings');
  return;
}

console.log('API ready! App ID:', window.byhunAPI.appId);

3. Basic Usage

All API methods return Promises, so use async/await or .then():

// Using async/await (recommended)
async function example() {
  try {
    const info = await window.byhunAPI.getSystemInfo();
    console.log('Platform:', info.platform);
    console.log('Version:', info.version);
  } catch (error) {
    console.error('Error:', error);
  }
}

// Using .then()
window.byhunAPI.getSystemInfo()
  .then(info => {
    console.log('System info:', info);
  })
  .catch(error => {
    console.error('Error:', error);
  });

API Reference

System Info

getSystemInfo()

Returns information about the system running Byhun.

Returns: Promise<Object>

Response:

{
  success: true,
  platform: "windows" | "android" | "linux" | "macos",
  version: "10.0.26100",  // OS version string
  sandboxEnabled: true
}

Example:

async function getSystemInfo() {
  try {
    const info = await window.byhunAPI.getSystemInfo();
    console.log(`Running on ${info.platform} ${info.version}`);
    return info;
  } catch (error) {
    console.error('Failed to get system info:', error);
  }
}

File Operations

All file paths are relative to your app's sandbox directory. You cannot access files outside the sandbox.

readFile(path: string)

Reads a file from the sandbox and returns its content as a string.

Parameters:

  • path (string): Relative path to the file (e.g., "data/config.json")

Returns: Promise<string> - File content as string

Example:

async function loadConfig() {
  try {
    const content = await window.byhunAPI.readFile('config.json');
    const config = JSON.parse(content);
    console.log('Config loaded:', config);
    return config;
  } catch (error) {
    console.error('Failed to read config:', error);
    // Return default config
    return { theme: 'dark', lang: 'en' };
  }
}

writeFile(path: string, content: string)

Writes content to a file in the sandbox. Creates parent directories if they don't exist.

Parameters:

  • path (string): Relative path to the file (e.g., "data/save.json")
  • content (string): Content to write to the file

Returns: Promise<Object>

Response:

{
  success: true,
  message: "File written successfully"
}

Example:

async function saveGame(saveData) {
  try {
    const content = JSON.stringify(saveData, null, 2);
    await window.byhunAPI.writeFile('saves/game1.json', content);
    console.log('Game saved successfully!');
  } catch (error) {
    console.error('Failed to save game:', error);
    alert('Failed to save game. Please try again.');
  }
}

// Save user preferences
async function savePreferences(prefs) {
  await window.byhunAPI.writeFile('preferences.json', JSON.stringify(prefs));
}

deleteFile(path: string)

Deletes a file from the sandbox.

Parameters:

  • path (string): Relative path to the file to delete

Returns: Promise<Object>

Response:

{
  success: true,
  message: "File deleted successfully"
}

Example:

async function deleteSave(saveName) {
  try {
    await window.byhunAPI.deleteFile(`saves/${saveName}.json`);
    console.log('Save file deleted');
  } catch (error) {
    console.error('Failed to delete save:', error);
  }
}

moveFile(sourcePath: string, destPath: string)

Moves (renames) a file from source path to destination path.

Parameters:

  • sourcePath (string): Current file path
  • destPath (string): New file path

Returns: Promise<Object>

Response:

{
  success: true,
  message: "File moved successfully"
}

Example:

async function renameSave(oldName, newName) {
  try {
    await window.byhunAPI.moveFile(
      `saves/${oldName}.json`,
      `saves/${newName}.json`
    );
    console.log('Save renamed');
  } catch (error) {
    console.error('Failed to rename save:', error);
  }
}

listFiles(directoryPath?: string)

Lists all files in a directory.

Parameters:

  • directoryPath (string, optional): Directory path. If not provided, lists root sandbox directory.

Returns: Promise<string[]> - Array of file paths

Example:

async function listSaves() {
  try {
    const files = await window.byhunAPI.listFiles('saves');
    console.log('Save files:', files);
    // Returns: ['game1.json', 'game2.json', ...]
    return files;
  } catch (error) {
    console.error('Failed to list saves:', error);
    return [];
  }
}

// List all files in sandbox root
async function listAllFiles() {
  const files = await window.byhunAPI.listFiles();
  console.log('All files:', files);
}

fileExists(path: string)

Checks if a file exists in the sandbox.

Parameters:

  • path (string): File path to check

Returns: Promise<boolean> - true if file exists, false otherwise

Example:

async function checkSaveExists(saveName) {
  const exists = await window.byhunAPI.fileExists(`saves/${saveName}.json`);
  if (exists) {
    console.log('Save file exists');
  } else {
    console.log('Save file does not exist');
  }
  return exists;
}

getFileInfo(path: string)

Gets detailed information about a file.

Parameters:

  • path (string): File path

Returns: Promise<Object>

Response:

{
  success: true,
  path: "data/config.json",
  size: 1024,  // File size in bytes
  modified: "2024-01-15T10:30:00.000Z",  // ISO 8601 timestamp
  isFile: true,
  isDirectory: false
}

Example:

async function getFileDetails(path) {
  try {
    const info = await window.byhunAPI.getFileInfo(path);
    console.log('File size:', info.size, 'bytes');
    console.log('Last modified:', new Date(info.modified));
    return info;
  } catch (error) {
    console.error('Failed to get file info:', error);
  }
}

Error Handling

All API methods can throw errors. Always use try-catch blocks:

async function safeFileOperation() {
  try {
    const content = await window.byhunAPI.readFile('data.json');
    // Process content
  } catch (error) {
    // Handle different error types
    if (error.message.includes('File not found')) {
      console.log('File does not exist, creating default...');
      await window.byhunAPI.writeFile('data.json', '{}');
    } else if (error.message.includes('SecurityException')) {
      console.error('Security violation!', error);
      alert('Invalid file path. Please contact app developer.');
    } else {
      console.error('Unexpected error:', error);
      alert('An error occurred. Please try again.');
    }
  }
}

Common Error Messages

  • "API is disabled" - Developer API is not enabled in settings
  • "API bridge not available" - API is not initialized
  • "File not found" - Requested file doesn't exist
  • "SecurityException: Path outside sandbox" - Attempted to access files outside sandbox
  • "App ID mismatch" - Internal security error (should not occur)

Security & Sandbox

Sandbox Isolation

Each app has its own isolated sandbox directory. Files cannot escape this directory, and apps cannot access files from other apps or the user's system.

Path Restrictions

  • Allowed: Relative paths like "data/file.json", "saves/game1.json"
  • Blocked: Absolute paths like "C:/Users/..." or "/etc/passwd"
  • Blocked: Path traversal attempts like "../../../etc/passwd"

All path traversal attempts (e.g., ../, ..\\) are automatically removed for security.

Best Practices

  1. Always validate paths before using them
  2. Never trust user input without sanitization
  3. Use subdirectories to organize files (e.g., saves/, data/, cache/)
  4. Handle errors gracefully and inform users

Examples

Example 1: Save/Load Game Data

class GameSaveManager {
  constructor() {
    this.saveDir = 'saves';
  }

  async saveGame(slotId, gameData) {
    try {
      const filename = `${this.saveDir}/slot${slotId}.json`;
      const content = JSON.stringify({
        ...gameData,
        savedAt: new Date().toISOString(),
        version: '1.0.0'
      }, null, 2);
      
      await window.byhunAPI.writeFile(filename, content);
      console.log(`Game saved to slot ${slotId}`);
      return true;
    } catch (error) {
      console.error('Save failed:', error);
      return false;
    }
  }

  async loadGame(slotId) {
    try {
      const filename = `${this.saveDir}/slot${slotId}.json`;
      const exists = await window.byhunAPI.fileExists(filename);
      
      if (!exists) {
        return null; // No save file
      }

      const content = await window.byhunAPI.readFile(filename);
      return JSON.parse(content);
    } catch (error) {
      console.error('Load failed:', error);
      return null;
    }
  }

  async listSaves() {
    try {
      // Ensure saves directory exists
      const files = await window.byhunAPI.listFiles(this.saveDir);
      return files.filter(f => f.endsWith('.json'));
    } catch (error) {
      // Directory might not exist yet
      return [];
    }
  }

  async deleteSave(slotId) {
    try {
      await window.byhunAPI.deleteFile(`${this.saveDir}/slot${slotId}.json`);
      return true;
    } catch (error) {
      console.error('Delete failed:', error);
      return false;
    }
  }
}

// Usage
const saveManager = new GameSaveManager();

// Save game
await saveManager.saveGame(1, {
  level: 5,
  score: 1000,
  playerName: 'Player1'
});

// Load game
const gameData = await saveManager.loadGame(1);
if (gameData) {
  console.log('Loaded:', gameData);
}

// List all saves
const saves = await saveManager.listSaves();
console.log('Available saves:', saves);

Example 2: Configuration Management

class ConfigManager {
  constructor(configPath = 'config.json') {
    this.configPath = configPath;
    this.defaultConfig = {
      theme: 'dark',
      language: 'en',
      volume: 0.7,
      notifications: true
    };
  }

  async loadConfig() {
    try {
      const exists = await window.byhunAPI.fileExists(this.configPath);
      if (!exists) {
        // Create default config
        await this.saveConfig(this.defaultConfig);
        return { ...this.defaultConfig };
      }

      const content = await window.byhunAPI.readFile(this.configPath);
      const config = JSON.parse(content);
      
      // Merge with defaults to ensure all keys exist
      return { ...this.defaultConfig, ...config };
    } catch (error) {
      console.error('Failed to load config:', error);
      return { ...this.defaultConfig };
    }
  }

  async saveConfig(config) {
    try {
      const content = JSON.stringify(config, null, 2);
      await window.byhunAPI.writeFile(this.configPath, content);
      return true;
    } catch (error) {
      console.error('Failed to save config:', error);
      return false;
    }
  }

  async updateConfig(key, value) {
    const config = await this.loadConfig();
    config[key] = value;
    return await this.saveConfig(config);
  }
}

// Usage
const configManager = new ConfigManager();

// Load configuration
const config = await configManager.loadConfig();
console.log('Current theme:', config.theme);

// Update a setting
await configManager.updateConfig('theme', 'light');

// Save full config
await configManager.saveConfig({
  theme: 'light',
  language: 'pt',
  volume: 0.8,
  notifications: false
});

Example 3: Cache Management

class CacheManager {
  constructor(cacheDir = 'cache') {
    this.cacheDir = cacheDir;
    this.maxCacheSize = 50 * 1024 * 1024; // 50 MB
  }

  async getCacheKey(key) {
    const filename = `${this.cacheDir}/${key}.cache`;
    const exists = await window.byhunAPI.fileExists(filename);
    
    if (!exists) {
      return null;
    }

    try {
      const info = await window.byhunAPI.getFileInfo(filename);
      const age = Date.now() - new Date(info.modified).getTime();
      const maxAge = 7 * 24 * 60 * 60 * 1000; // 7 days

      if (age > maxAge) {
        // Cache expired
        await window.byhunAPI.deleteFile(filename);
        return null;
      }

      const content = await window.byhunAPI.readFile(filename);
      return JSON.parse(content);
    } catch (error) {
      console.error('Cache read error:', error);
      return null;
    }
  }

  async setCacheKey(key, data) {
    const filename = `${this.cacheDir}/${key}.cache`;
    try {
      const content = JSON.stringify({
        data,
        cachedAt: new Date().toISOString()
      });
      
      await window.byhunAPI.writeFile(filename, content);
      return true;
    } catch (error) {
      console.error('Cache write error:', error);
      return false;
    }
  }

  async clearCache() {
    try {
      const files = await window.byhunAPI.listFiles(this.cacheDir);
      for (const file of files) {
        await window.byhunAPI.deleteFile(`${this.cacheDir}/${file}`);
      }
      return true;
    } catch (error) {
      console.error('Cache clear error:', error);
      return false;
    }
  }

  async getCacheSize() {
    try {
      const files = await window.byhunAPI.listFiles(this.cacheDir);
      let totalSize = 0;

      for (const file of files) {
        const info = await window.byhunAPI.getFileInfo(`${this.cacheDir}/${file}`);
        totalSize += info.size;
      }

      return totalSize;
    } catch (error) {
      return 0;
    }
  }
}

// Usage
const cache = new CacheManager();

// Cache data
await cache.setCacheKey('userData', { name: 'John', id: 123 });

// Retrieve from cache
const userData = await cache.getCacheKey('userData');
if (userData) {
  console.log('From cache:', userData);
} else {
  console.log('Cache miss, fetching...');
  // Fetch from server...
}

// Clear old cache
const size = await cache.getCacheSize();
if (size > cache.maxCacheSize) {
  await cache.clearCache();
}

Example 4: System Information Display

async function displaySystemInfo() {
  try {
    const info = await window.byhunAPI.getSystemInfo();
    
    const infoDiv = document.getElementById('system-info');
    infoDiv.innerHTML = `
      <h3>System Information</h3>
      <p><strong>Platform:</strong> ${info.platform}</p>
      <p><strong>Version:</strong> ${info.version}</p>
      <p><strong>Sandbox:</strong> ${info.sandboxEnabled ? 'Enabled' : 'Disabled'}</p>
    `;
  } catch (error) {
    console.error('Failed to get system info:', error);
  }
}

// Call on page load
window.addEventListener('DOMContentLoaded', displaySystemInfo);

Best Practices

1. Always Check API Availability

function checkAPI() {
  if (typeof window.byhunAPI === 'undefined' || !window.byhunAPI.enabled) {
    alert('Developer API is not enabled. Please enable it in Byhun settings.');
    return false;
  }
  return true;
}

if (!checkAPI()) {
  // Fallback behavior
  console.warn('Using fallback storage (localStorage)');
}

2. Use Async/Await for Cleaner Code

// ✅ Good
async function loadData() {
  try {
    const data = await window.byhunAPI.readFile('data.json');
    return JSON.parse(data);
  } catch (error) {
    console.error(error);
    return null;
  }
}

// ❌ Avoid deeply nested promises
function loadData() {
  window.byhunAPI.readFile('data.json')
    .then(data => {
      JSON.parse(data)
        .then(result => {
          // Process result
        })
        .catch(error => {
          // Handle error
        });
    })
    .catch(error => {
      // Handle error
    });
}

3. Organize Files with Directories

// ✅ Good - organized structure
await window.byhunAPI.writeFile('saves/game1.json', data);
await window.byhunAPI.writeFile('config/settings.json', config);
await window.byhunAPI.writeFile('cache/data.cache', cache);

// ❌ Avoid - flat structure
await window.byhunAPI.writeFile('game1.json', data);
await window.byhunAPI.writeFile('settings.json', config);
await window.byhunAPI.writeFile('data.cache', cache);

4. Handle Errors Gracefully

async function safeOperation(path) {
  try {
    return await window.byhunAPI.readFile(path);
  } catch (error) {
    if (error.message.includes('not found')) {
      // File doesn't exist - not necessarily an error
      return null;
    } else {
      // Real error - log and handle
      console.error('Operation failed:', error);
      showErrorToUser('An error occurred. Please try again.');
      return null;
    }
  }
}

5. Validate User Input

function sanitizePath(userInput) {
  // Remove dangerous characters and path traversal
  return userInput
    .replace(/[<>:"|?*]/g, '') // Remove invalid characters
    .replace(/\.\./g, '')       // Remove path traversal
    .replace(/^\/+/, '');       // Remove leading slashes
}

async function saveUserFile(userInput, content) {
  const safePath = sanitizePath(userInput);
  if (!safePath) {
    throw new Error('Invalid file name');
  }
  
  await window.byhunAPI.writeFile(`user-files/${safePath}`, content);
}

6. Use Helper Classes

Create reusable helper classes for common operations (see examples above) to keep your code clean and maintainable.


Troubleshooting

API Not Available

Problem: window.byhunAPI is undefined

Solutions:

  1. Ensure the app is running in Byhun WebView (not in a regular browser)
  2. Check that Developer API is enabled in Byhun settings
  3. Verify the page has loaded completely before accessing the API

File Not Found Errors

Problem: File not found errors when files should exist

Solutions:

  1. Check file paths - they are case-sensitive
  2. Ensure files are being created before trying to read them
  3. Use fileExists() to check before reading

Permission Errors

Problem: Security exceptions or permission errors

Solutions:

  1. Ensure paths are relative (not absolute)
  2. Avoid path traversal sequences (../, ..\\)
  3. Verify Developer API is enabled
  4. Check that App ID matches (should happen automatically)

Support

For issues or questions about the Developer API:

  1. Check this documentation first
  2. Review error messages carefully
  3. Ensure Developer API is enabled in settings
  4. Verify your code follows security best practices

Version History

  • v1.0.0 (Current) - Initial API release
    • System information
    • File operations (read, write, delete, move)
    • File listing and information
    • Sandbox security

Happy Coding! 🚀