A TypeScript library for safe dynamic code execution using new Function() that works in both Node.js and browser environments.
β
Universal Compatibility - Works in both Node.js and browser environments
β
TypeScript Support - Full type safety with comprehensive type definitions
β
Singleton Pattern - Initialize once, use anywhere
β
Module Imports - Pre-define classes and functions for dynamic code
β
Proxy-based Sandbox - Safe variable access control with proxy mechanism
β
Configurable Security - Fine-grained control over allowed APIs and operations
β
Form Class Creation - Special method for creating dynamic form classes
β
Multiple Build Formats - CommonJS and ESM support
β
Performance Monitoring - Built-in execution time tracking
npm install @ticatec/dyna-jsimport { initializeDynaJs } from '@ticatec/dyna-js';
// Initialize with your classes and functions
initializeDynaJs({
defaultImports: {
FlexiForm: FlexiFormClass,
FlexiCard: FlexiCardClass,
Dialog: DialogClass,
MessageBox: MessageBoxClass,
FlexiContext: FlexiContextClass,
ModuleLoader: ModuleLoaderClass
},
defaultInjectedKeys: ['Dialog', 'MessageBox', 'Indicator', 'Toast'],
useProxyByDefault: true,
allowBrowserAPIs: false, // Secure by default
validateCode: true
});import { getDynaJs } from '@ticatec/dyna-js';
// Get the initialized loader
const loader = getDynaJs();
// Create form classes
const MyFormClass = loader.createFormClass(`
class CustomForm extends FlexiForm {
constructor() {
super();
this.dialog = Dialog; // Auto-injected
}
show() {
MessageBox.info('Form is ready!'); // Auto-injected
}
render() {
return new FlexiCard({
title: 'Dynamic Form',
content: 'Created dynamically!'
});
}
}
return CustomForm;
`);
// Instantiate and use
const form = new MyFormClass();
form.show();Creates a form class with proxy-based sandbox execution.
const FormClass = loader.createFormClass(`
class MyForm extends FlexiForm {
constructor() {
super();
this.setupDialog();
}
setupDialog() {
this.dialog = new Dialog({
title: 'Dynamic Dialog'
});
}
}
return MyForm;
`, {
customData: 'additional context'
}, ['extraKey']);Synchronously execute code with result and timing information.
const result = loader.executeSync(`
const form = new FlexiForm();
form.setTitle('Dynamic Form');
return form;
`);
console.log(result.result); // FlexiForm instance
console.log(result.executionTime); // Execution time in millisecondsAsynchronously execute code with timeout support.
const result = await loader.execute(`
return new Promise(resolve => {
const form = new FlexiForm();
resolve(form);
});
`, {
timeout: 3000,
context: { customVar: 'value' }
});executeWithImports<T>(code: string, imports: object, options?: ExecutionOptions): ExecutionResult<T>
Execute code with additional temporary imports.
const result = loader.executeWithImports(`
return new CustomComponent({
message: 'Hello from dynamic code!'
});
`, {
CustomComponent: MyCustomComponent,
utils: myUtilsLibrary
});interface DynaJsConfig {
defaultTimeout?: number; // Default: 5000ms
defaultStrict?: boolean; // Default: true
allowedGlobals?: string[]; // Whitelist of allowed global variables
blockedGlobals?: string[]; // Blacklist of blocked variables
defaultImports?: object; // Pre-imported classes/functions
defaultInjectedKeys?: string[]; // Auto-injected variable names
useProxyByDefault?: boolean; // Default: true
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)
allowNodeAPIs?: boolean; // Allow process/require access (Default: false)
}initializeDynaJs({
defaultImports: { FlexiForm, Dialog },
allowBrowserAPIs: false, // Block window, document, localStorage
allowNodeAPIs: false, // Block process, require
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)initializeDynaJs({
defaultImports: { FlexiForm, Dialog },
allowBrowserAPIs: true, // β
Allow browser APIs
allowTimers: true, // β
Allow timers
allowDynamicImports: true, // β
Allow dynamic imports
validateCode: false // Disable validation
});
// β
Now allowed:
// document.getElementById('myDiv')
// localStorage.getItem('data')
// setTimeout(() => {}, 1000)initializeDynaJs({
defaultImports: {
FlexiForm, Dialog, MessageBox,
// Provide safe DOM access
safeDOM: {
getElementById: (id) => document.getElementById(id),
createElement: (tag) => document.createElement(tag)
}
},
allowBrowserAPIs: false, // Still secure
allowTimers: false, // No timers needed for forms
validateCode: true, // Keep validation
defaultInjectedKeys: ['window'] // Only inject window reference
});const DynamicFormBuilder = loader.createFormClass(`
class FormBuilder extends FlexiForm {
constructor(config) {
super();
this.config = config;
this.components = [];
}
addField(fieldConfig) {
const field = new FlexiCard({
title: fieldConfig.label,
content: this.createInput(fieldConfig.type)
});
this.components.push(field);
return this;
}
createInput(type) {
switch(type) {
case 'text':
return '<input type="text" />';
case 'number':
return '<input type="number" />';
default:
return '<input type="text" />';
}
}
build() {
return this.components;
}
show() {
const dialog = new Dialog({
title: this.config.title,
content: this.render()
});
dialog.show();
}
render() {
return this.components.map(c => c.render()).join('');
}
}
return FormBuilder;
`);
// Use the dynamically created form builder
const formBuilder = new DynamicFormBuilder({
title: 'Dynamic Contact Form'
});
formBuilder
.addField({ label: 'Name', type: 'text' })
.addField({ label: 'Age', type: 'number' })
.show();const dynamicValidator = loader.createFunction(`
return function validateForm(formData) {
const errors = [];
if (!formData.name) {
errors.push('Name is required');
}
if (!formData.email || !formData.email.includes('@')) {
errors.push('Valid email is required');
}
return {
isValid: errors.length === 0,
errors: errors
};
};
`, []);
// Use the dynamic function
const validation = dynamicValidator({
name: 'John',
email: 'john@example.com'
});try {
const result = loader.executeSync(`
// Some dynamic code that might fail
return new NonExistentClass();
`);
} catch (error) {
console.error('Execution failed:', error.message);
// Error includes execution time and detailed error information
}- Chrome 51+
- Firefox 40+
- Safari 10+
- Edge 14+
- Node.js 14+
Full TypeScript support with comprehensive type definitions:
import {
DynaJs,
ExecutionResult,
ExecutionOptions,
ModuleImports
} from '@ticatec/dyna-js';- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT License - see the LICENSE file for details.
- Code Validation: Always keep
validateCode: truein production - API Restrictions: Be careful when enabling
allowBrowserAPIsorallowNodeAPIs - Input Sanitization: Validate all dynamic code input from external sources
- Timeout Settings: Set appropriate timeouts to prevent infinite loops
- Principle of Least Privilege: Only import the minimum required functions and classes
For issues and feature requests, please use the GitHub Issues page.