npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ticatec/dyna-js

v0.2.1

Published

A modern TypeScript library for safe dynamic code execution in browser environments with intelligent module caching and configurable security policies

Readme

@ticatec/dyna-js

npm version License: MIT TypeScript

中文文档

A modern TypeScript library for safe dynamic code execution in browser environments using new Function() with configurable security policies and intelligent module caching.

✨ Features

🚀 Modern Browser Library - Built for modern browsers with ESM modules only
🔒 Secure by Default - Configurable security policies to control code execution
Performance Optimized - Parallel module loading and intelligent caching
💾 Smart Storage - Unified localStorage management with version control
📦 TypeScript Support - Full type safety with comprehensive type definitions
🎯 Singleton Pattern - Initialize once, use anywhere
🔧 Developer Friendly - Simple API with powerful features

📦 Installation

npm install @ticatec/dyna-js

🚀 Quick Start

1. Initialize DynaJs (Application Startup)

import { initializeDynaJs } from '@ticatec/dyna-js';

// Initialize with your classes and functions
initializeDynaJs({
  defaultImports: {
    FlexiForm: FlexiFormClass,
    Dialog: DialogClass,
    MessageBox: MessageBoxClass
  },
  allowBrowserAPIs: false,  // Secure by default
  validateCode: true
});

2. Execute Dynamic Code

import { getDynaJs } from '@ticatec/dyna-js';

const loader = getDynaJs();

// Create dynamic form class
const MyFormClass = loader.executeSync(`
  class CustomForm extends FlexiForm {
    constructor() {
      super();
      this.dialog = Dialog;
    }

    show() {
      MessageBox.info('Form is ready!');
    }

    render() {
      return `
        <div class="form">
          <h1>Dynamic Form</h1>
          <p>Created dynamically!</p>
        </div>
      `;
    }
  }
  return CustomForm;
`);

// Use the dynamically created class
const form = new MyFormClass();
form.show();

📚 API Reference

DynaJs

executeSync<T>(code: string, options?: ExecutionOptions): T

Synchronously execute code and return the result.

const result = loader.executeSync(`
  return new FlexiForm();
`);

execute<T>(code: string, options?: ExecutionOptions): Promise<T>

Asynchronously execute code with timeout support.

const result = await loader.execute(`
  return await fetchData();
`, { timeout: 3000 });

createFunction<T>(code: string, paramNames?: string[], options?: ExecutionOptions): T

Create a reusable function from dynamic code.

const validator = loader.createFunction(`
  return function(data) {
    return data.name && data.email;
  };
`);

const isValid = validator({ name: 'John', email: '[email protected]' });

Configuration Options

interface DynaJsConfig {
  defaultTimeout?: number;           // Default: 5000ms
  defaultStrict?: boolean;           // Default: true
  allowedGlobals?: string[];         // Whitelist of allowed global variables
  blockedGlobals?: string[];         // Blacklist of blocked variables
  defaultImports?: ModuleImports;    // Pre-imported classes/functions
  allowTimers?: boolean;             // Allow setTimeout/setInterval (Default: false)
  allowDynamicImports?: boolean;     // Allow import()/require() (Default: false)
  validateCode?: boolean;            // Enable code validation (Default: true)
  allowBrowserAPIs?: boolean;        // Allow window/document access (Default: false)
}

🔐 Security Configurations

🔒 Strict Mode (Recommended, Default)

initializeDynaJs({
  defaultImports: { FlexiForm, Dialog },
  allowBrowserAPIs: false,    // Block window, document, localStorage
  allowTimers: false,         // Block setTimeout/setInterval
  validateCode: true          // Enable code pattern validation
});

// ❌ These will be blocked:
// window.location.href = 'malicious-site.com'
// localStorage.clear()
// setTimeout(maliciousFunction, 1000)

🟡 Permissive Mode

initializeDynaJs({
  defaultImports: { FlexiForm, Dialog },
  allowBrowserAPIs: true,     // ✅ Allow browser APIs
  allowTimers: true,          // ✅ Allow timers
  validateCode: false         // Disable validation
});

📦 ModuleLoader - Dynamic Module Management

ModuleLoader manages dynamic JavaScript modules with automatic caching, version control, and parallel loading.

Basic Usage

1. Initialize ModuleLoader

import { ModuleLoader } from '@ticatec/dyna-js';

const loadModule = async (moduleInfo) => {
  const response = await fetch(`/api/modules/${moduleInfo.code}`);
  return response.json(); // Should return { code, digest, scriptText, uiLayout? }
};

const moduleLoader = ModuleLoader.initialize(loadModule, {
  keyField: 'code',      // Default: 'code'
  prefix: 'MyApp'        // Default: 'DynaJS'
});

2. Check and Update Modules (Parallel Loading)

// Check and update all stale modules in parallel
await moduleLoader.checkFreshScripts([
  { code: 'user-form', digest: 'abc123...' },
  { code: 'data-grid', digest: 'def456...' },
  { code: 'chart-widget', digest: 'ghi789...' }
]);

// Performance: If 3 modules need updating:
// Serial:   200ms + 300ms + 250ms = 750ms
// Parallel: max(200ms, 300ms, 250ms) = 300ms ✅

3. Create and Use Modules

const UserForm = moduleLoader.createModule('user-form', {
  React,
  ReactDOM,
  Dialog
});

const form = new UserForm({ title: 'User Registration' });

ModuleLoader API Reference

Static Methods

ModuleLoader.initialize(loadModule, options?)

Initialize or get the ModuleLoader singleton instance.

const loader = ModuleLoader.initialize(
  async (info) => {
    const response = await fetch(`/api/modules/${info.code}`);
    return response.json();
  },
  {
    keyField: 'code',        // Field name for module identifier
    prefix: 'MyApp',         // Storage prefix for localStorage
    moduleCheck: customCheck // Optional custom freshness check
  }
);

Parameters:

  • loadModule (LoadModule): Function to fetch module data from remote
  • options (ModuleLoaderOptions): Optional configuration
    • keyField: Field name containing module identifier (default: 'code')
    • prefix: Storage prefix for localStorage keys (default: 'DynaJS')
    • moduleCheck: Custom function to check if module needs update

Returns: The singleton ModuleLoader instance


ModuleLoader.getInstance()

Get the existing ModuleLoader singleton instance. Throws if not initialized.

// In main file
ModuleLoader.initialize(loadFn, options);

// In another file
const loader = ModuleLoader.getInstance();

Returns: The ModuleLoader instance Throws: Error if instance has not been initialized


ModuleLoader.reset()

Reset the singleton instance. Primarily useful for testing.

afterEach(() => {
  ModuleLoader.reset();
});

Instance Methods

checkFreshScripts(list)

Check and update modules that are not fresh. Performs parallel loading for optimal performance.

await loader.checkFreshScripts([
  { code: 'user-form', digest: 'abc123' },
  { code: 'data-grid', digest: 'def456' }
]);

Parameters:

  • list (Array): Array of module data objects to check

Returns: Promise that resolves when all modules are checked and updated

Performance: Parallel loading is N× faster than serial for N modules


createModule<T>(key, imports)

Create or retrieve a cached module instance.

// Create a React component class
const UserForm = loader.createModule<typeof React.Component>('user-form', {
  React,
  ReactDOM,
  Dialog
});

const form = new UserForm({ title: 'User Registration' });

Parameters:

  • key (string): The module key/code to load
  • imports (any): Object containing dependencies to inject into module scope

Returns: The instantiated module or cached instance

Throws: Error if module not found in storage (call checkFreshScripts first)


getLayout<T>(key)

Get the UI layout configuration for a module.

interface FormLayout {
  fields: Array<{ name: string; type: string }>;
  structure: Record<string, any>;
}

const layout = loader.getLayout<FormLayout>('user-form');
if (layout) {
  console.log('Form fields:', layout.fields);
  console.log('Form structure:', layout.structure);
}

Parameters:

  • key (string): Module identifier

Returns: Parsed layout object or null if not found


getDigest(key)

Get the current digest (version hash) for a module.

const digest = loader.getDigest('user-form');
console.log(`Current version: ${digest?.substring(0, 8)}`);

Parameters:

  • key (string): Module identifier

Returns: Digest string or null if module not found


removeModule(key)

Remove a specific module from localStorage and memory cache.

loader.removeModule('deprecated-form');

Parameters:

  • key (string): Module identifier

clearAll()

Clear all modules from localStorage and memory cache.

const count = loader.clearAll();
console.log(`Cleared ${count} modules`);

Returns: Number of modules cleared


getAllModuleKeys()

Get all module keys currently stored in localStorage.

const keys = loader.getAllModuleKeys();
console.log('Available modules:', keys);
// ['user-form', 'data-grid', 'chart-widget', ...]

Returns: Array of module keys


getStorageStats()

Get storage usage statistics for all modules.

const stats = loader.getStorageStats();
console.log(`Modules: ${stats.moduleCount}`);
console.log(`Total size: ${(stats.totalSize / 1024).toFixed(2)} KB`);

// Find old modules for cleanup
const oldModules = stats.modules.filter(
  m => Date.now() - m.timestamp > 30 * 24 * 60 * 60 * 1000
);

Returns: Object containing:

  • moduleCount (number): Total number of modules
  • totalSize (number): Total storage size in bytes
  • modules (Array): Per-module details with key, size, and timestamp

StorageManager - Unified Storage API

StorageManager provides a unified API for localStorage operations with built-in error handling and version control.

import { StorageManager } from '@ticatec/dyna-js';

// Get storage statistics
const stats = StorageManager.getStorageStats('MyApp');
console.log(`Modules: ${stats.moduleCount}, Size: ${stats.totalSize} bytes`);

// Get all module keys
const keys = StorageManager.getAllModuleKeys('MyApp');

// Clear all modules
const count = StorageManager.clearAll('MyApp');

// Check if module is fresh
const isFresh = StorageManager.isModuleFresh('MyApp', 'module-name', 'digest-value');

Storage Data Structure

Modules are stored as a single JSON object:

{
  metadata: {
    digest: string;      // Version hash
    version: number;     // Storage format version
    timestamp: number;   // Last update time
    size: number;        // Script size in bytes
  },
  scriptText: string;    // The actual code
  uiLayout?: string;     // Optional UI layout (JSON string)
}

🎯 Use Cases

Dynamic Form Components

const DynamicFormBuilder = loader.executeSync(`
  class FormBuilder extends FlexiForm {
    constructor(config) {
      super();
      this.config = config;
      this.fields = [];
    }

    addField(fieldConfig) {
      this.fields.push(fieldConfig);
      return this;
    }

    build() {
      return this.fields.map(field =>
        new FlexiCard({ title: field.label })
      );
    }
  }

  return FormBuilder;
`);

Validation Functions

const validator = loader.createFunction(`
  return function validateEmail(email) {
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
  };
`);

validator('[email protected]'); // true

🔧 Advanced Usage

Storage Management

// Monitor storage usage
const stats = moduleLoader.getStorageStats();
if (stats.totalSize > 5_000_000) { // 5MB
  console.warn('Storage quota running low!');

  // Clear old modules
  const oldModules = stats.modules
    .filter(m => Date.now() - m.timestamp > 30 * 24 * 60 * 60 * 1000)
    .map(m => m.key);

  oldModules.forEach(key => moduleLoader.removeModule(key));
}

Custom Module Check

const moduleLoader = ModuleLoader.initialize(loadModule, {
  moduleCheck: (moduleInfo) => {
    // Custom freshness check logic
    const localData = StorageManager.loadModule('MyApp', moduleInfo.code);
    return localData?.metadata.digest === moduleInfo.digest;
  }
});

🌐 Browser Support

  • Chrome 90+
  • Firefox 88+
  • Safari 14+
  • Edge 90+

Requirement: Modern browsers with ES2020+ support

📝 TypeScript Support

Full TypeScript support with comprehensive type definitions:

import {
  DynaJs,
  ModuleLoader,
  StorageManager,
  StorageKey,
  ExecutionOptions,
  ModuleImports,
  StoredModuleData,
  ModuleMetadata
} from '@ticatec/dyna-js';

🏗️ Building

npm run build          # Build ESM modules
npm run build:watch    # Watch mode
npm run typecheck      # Type checking only
npm run clean          # Clean dist directory

🤝 Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

MIT License - see the LICENSE file for details.

⚠️ Security Considerations

  1. Code Validation: Always keep validateCode: true in production
  2. API Restrictions: Be careful when enabling allowBrowserAPIs
  3. Input Sanitization: Validate all dynamic code input from external sources
  4. Timeout Settings: Set appropriate timeouts to prevent infinite loops
  5. Principle of Least Privilege: Only import the minimum required functions/classes

💡 Best Practices

  1. Storage Quota: Monitor storage usage and implement cleanup strategies
  2. Version Control: Use content-based hashing (MD5, SHA-256) for digests
  3. Error Handling: Wrap module creation in try-catch blocks
  4. Parallel Loading: Use checkFreshScripts() with multiple modules for better performance
  5. Cache Invalidation: Check for updates on app startup

📞 Support

For issues and feature requests, please use the GitHub Issues page.