@ticatec/dyna-js 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -12
- package/README_CN.md +26 -24
- package/dist/DynaJs.d.ts +200 -5
- package/dist/DynaJs.d.ts.map +1 -1
- package/dist/DynaJs.esm.js +199 -10
- package/dist/DynaJs.js +199 -10
- package/dist/types.d.ts +0 -6
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ const MyFormClass = loader.executeSync(`
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
return CustomForm;
|
|
78
|
-
`)
|
|
78
|
+
`);
|
|
79
79
|
|
|
80
80
|
// Instantiate and use
|
|
81
81
|
const form = new MyFormClass();
|
|
@@ -86,27 +86,27 @@ form.show();
|
|
|
86
86
|
|
|
87
87
|
### Core Methods
|
|
88
88
|
|
|
89
|
-
#### `executeSync<T>(code: string, options?: ExecutionOptions):
|
|
89
|
+
#### `executeSync<T>(code: string, options?: ExecutionOptions): T`
|
|
90
90
|
|
|
91
|
-
Synchronously execute code
|
|
91
|
+
Synchronously execute code and return the result directly.
|
|
92
92
|
|
|
93
93
|
```typescript
|
|
94
|
-
const
|
|
94
|
+
const form = loader.executeSync(`
|
|
95
95
|
const form = new FlexiForm();
|
|
96
96
|
form.setTitle('Dynamic Form');
|
|
97
97
|
return form;
|
|
98
98
|
`);
|
|
99
99
|
|
|
100
|
-
console.log(
|
|
101
|
-
|
|
100
|
+
console.log(form); // FlexiForm instance
|
|
101
|
+
// Execution time is logged to console automatically
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
#### `execute<T>(code: string, options?: ExecutionOptions): Promise<
|
|
104
|
+
#### `execute<T>(code: string, options?: ExecutionOptions): Promise<T>`
|
|
105
105
|
|
|
106
106
|
Asynchronously execute code with timeout support.
|
|
107
107
|
|
|
108
108
|
```typescript
|
|
109
|
-
const
|
|
109
|
+
const form = await loader.execute(`
|
|
110
110
|
return new Promise(resolve => {
|
|
111
111
|
const form = new FlexiForm();
|
|
112
112
|
resolve(form);
|
|
@@ -115,14 +115,16 @@ const result = await loader.execute(`
|
|
|
115
115
|
timeout: 3000,
|
|
116
116
|
context: { customVar: 'value' }
|
|
117
117
|
});
|
|
118
|
+
|
|
119
|
+
console.log(form); // FlexiForm instance
|
|
118
120
|
```
|
|
119
121
|
|
|
120
|
-
#### `executeWithImports<T>(code: string, imports: object, options?: ExecutionOptions):
|
|
122
|
+
#### `executeWithImports<T>(code: string, imports: object, options?: ExecutionOptions): T`
|
|
121
123
|
|
|
122
124
|
Execute code with additional temporary imports.
|
|
123
125
|
|
|
124
126
|
```typescript
|
|
125
|
-
const
|
|
127
|
+
const component = loader.executeWithImports(`
|
|
126
128
|
return new CustomComponent({
|
|
127
129
|
message: 'Hello from dynamic code!'
|
|
128
130
|
});
|
|
@@ -254,7 +256,7 @@ const DynamicFormBuilder = loader.executeSync(`
|
|
|
254
256
|
}
|
|
255
257
|
|
|
256
258
|
return FormBuilder;
|
|
257
|
-
`)
|
|
259
|
+
`);
|
|
258
260
|
|
|
259
261
|
// Use the dynamically created form builder
|
|
260
262
|
const formBuilder = new DynamicFormBuilder({
|
|
@@ -306,7 +308,7 @@ try {
|
|
|
306
308
|
`);
|
|
307
309
|
} catch (error) {
|
|
308
310
|
console.error('Execution failed:', error.message);
|
|
309
|
-
// Error includes execution time and detailed error information
|
|
311
|
+
// Error message includes execution time and detailed error information
|
|
310
312
|
}
|
|
311
313
|
```
|
|
312
314
|
|
package/README_CN.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/js/@ticatec%2Fdyna-js)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
|
-
[](http://www.typescriptlang.org
|
|
5
|
+
[](http://www.typescriptlang.org())
|
|
6
6
|
[](https://nodejs.org/)
|
|
7
7
|
|
|
8
8
|
[English Documentation](README.md)
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
✅ **模块导入** - 为动态代码预定义类和函数
|
|
18
18
|
✅ **可配置安全性** - 对允许的 API 和操作进行细粒度控制
|
|
19
19
|
✅ **多种构建格式** - 支持 CommonJS 和 ESM
|
|
20
|
-
✅ **性能监控** - 内置执行时间跟踪
|
|
20
|
+
✅ **性能监控** - 内置执行时间跟踪
|
|
21
21
|
|
|
22
22
|
## 安装
|
|
23
23
|
|
|
@@ -75,7 +75,7 @@ const MyFormClass = loader.executeSync(`
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
return CustomForm;
|
|
78
|
-
`)
|
|
78
|
+
`);
|
|
79
79
|
|
|
80
80
|
// 实例化并使用
|
|
81
81
|
const form = new MyFormClass();
|
|
@@ -86,27 +86,27 @@ form.show();
|
|
|
86
86
|
|
|
87
87
|
### 核心方法
|
|
88
88
|
|
|
89
|
-
#### `executeSync<T>(code: string, options?: ExecutionOptions):
|
|
89
|
+
#### `executeSync<T>(code: string, options?: ExecutionOptions): T`
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
同步执行代码并直接返回结果。
|
|
92
92
|
|
|
93
93
|
```typescript
|
|
94
|
-
const
|
|
94
|
+
const form = loader.executeSync(`
|
|
95
95
|
const form = new FlexiForm();
|
|
96
96
|
form.setTitle('动态表单');
|
|
97
97
|
return form;
|
|
98
98
|
`);
|
|
99
99
|
|
|
100
|
-
console.log(
|
|
101
|
-
|
|
100
|
+
console.log(form); // FlexiForm 实例
|
|
101
|
+
// 执行时间会自动记录到控制台
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
#### `execute<T>(code: string, options?: ExecutionOptions): Promise<
|
|
104
|
+
#### `execute<T>(code: string, options?: ExecutionOptions): Promise<T>`
|
|
105
105
|
|
|
106
106
|
异步执行代码,支持超时控制。
|
|
107
107
|
|
|
108
108
|
```typescript
|
|
109
|
-
const
|
|
109
|
+
const form = await loader.execute(`
|
|
110
110
|
return new Promise(resolve => {
|
|
111
111
|
const form = new FlexiForm();
|
|
112
112
|
resolve(form);
|
|
@@ -115,14 +115,16 @@ const result = await loader.execute(`
|
|
|
115
115
|
timeout: 3000,
|
|
116
116
|
context: { customVar: 'value' }
|
|
117
117
|
});
|
|
118
|
+
|
|
119
|
+
console.log(form); // FlexiForm 实例
|
|
118
120
|
```
|
|
119
121
|
|
|
120
|
-
#### `executeWithImports<T>(code: string, imports: object, options?: ExecutionOptions):
|
|
122
|
+
#### `executeWithImports<T>(code: string, imports: object, options?: ExecutionOptions): T`
|
|
121
123
|
|
|
122
124
|
使用额外的临时导入执行代码。
|
|
123
125
|
|
|
124
126
|
```typescript
|
|
125
|
-
const
|
|
127
|
+
const component = loader.executeWithImports(`
|
|
126
128
|
return new CustomComponent({
|
|
127
129
|
message: '来自动态代码的问候!'
|
|
128
130
|
});
|
|
@@ -254,7 +256,7 @@ const DynamicFormBuilder = loader.executeSync(`
|
|
|
254
256
|
}
|
|
255
257
|
|
|
256
258
|
return FormBuilder;
|
|
257
|
-
`)
|
|
259
|
+
`);
|
|
258
260
|
|
|
259
261
|
// 使用动态创建的表单构建器
|
|
260
262
|
const formBuilder = new DynamicFormBuilder({
|
|
@@ -273,15 +275,15 @@ formBuilder
|
|
|
273
275
|
const dynamicValidator = loader.createFunction(`
|
|
274
276
|
return function validateForm(formData) {
|
|
275
277
|
const errors = [];
|
|
276
|
-
|
|
278
|
+
|
|
277
279
|
if (!formData.name) {
|
|
278
280
|
errors.push('姓名是必填项');
|
|
279
281
|
}
|
|
280
|
-
|
|
282
|
+
|
|
281
283
|
if (!formData.email || !formData.email.includes('@')) {
|
|
282
284
|
errors.push('需要有效的邮箱地址');
|
|
283
285
|
}
|
|
284
|
-
|
|
286
|
+
|
|
285
287
|
return {
|
|
286
288
|
isValid: errors.length === 0,
|
|
287
289
|
errors: errors
|
|
@@ -306,7 +308,7 @@ try {
|
|
|
306
308
|
`);
|
|
307
309
|
} catch (error) {
|
|
308
310
|
console.error('执行失败:', error.message);
|
|
309
|
-
//
|
|
311
|
+
// 错误信息包含执行时间和详细的错误信息
|
|
310
312
|
}
|
|
311
313
|
```
|
|
312
314
|
|
|
@@ -323,11 +325,11 @@ try {
|
|
|
323
325
|
具有完整类型定义的 TypeScript 支持:
|
|
324
326
|
|
|
325
327
|
```typescript
|
|
326
|
-
import {
|
|
328
|
+
import {
|
|
327
329
|
DynaJs,
|
|
328
330
|
ExecutionResult,
|
|
329
331
|
ExecutionOptions,
|
|
330
|
-
ModuleImports
|
|
332
|
+
ModuleImports
|
|
331
333
|
} from '@ticatec/dyna-js';
|
|
332
334
|
```
|
|
333
335
|
|
|
@@ -364,9 +366,9 @@ MIT 许可证 - 详情请查看 [LICENSE](LICENSE) 文件。
|
|
|
364
366
|
### 动态表单创建
|
|
365
367
|
```typescript
|
|
366
368
|
// 适合创建各种动态表单组件
|
|
367
|
-
const ContactForm = loader.executeSync(`...`)
|
|
368
|
-
const SurveyForm = loader.executeSync(`...`)
|
|
369
|
-
const RegistrationForm = loader.executeSync(`...`)
|
|
369
|
+
const ContactForm = loader.executeSync(`...`);
|
|
370
|
+
const SurveyForm = loader.executeSync(`...`);
|
|
371
|
+
const RegistrationForm = loader.executeSync(`...`);
|
|
370
372
|
```
|
|
371
373
|
|
|
372
374
|
### 业务规则执行
|
|
@@ -377,7 +379,7 @@ const businessRule = loader.executeSync(`
|
|
|
377
379
|
// 复杂的业务逻辑
|
|
378
380
|
return processBusinessRule(data);
|
|
379
381
|
};
|
|
380
|
-
`)
|
|
382
|
+
`);
|
|
381
383
|
```
|
|
382
384
|
|
|
383
385
|
### 模板渲染
|
|
@@ -391,5 +393,5 @@ const templateEngine = loader.executeSync(`
|
|
|
391
393
|
}
|
|
392
394
|
}
|
|
393
395
|
return TemplateEngine;
|
|
394
|
-
`)
|
|
396
|
+
`);
|
|
395
397
|
```
|
package/dist/DynaJs.d.ts
CHANGED
|
@@ -1,18 +1,213 @@
|
|
|
1
|
-
import { ExecutionOptions,
|
|
1
|
+
import { ExecutionOptions, DynaJsConfig, ModuleImports } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* DynaJs - A safe dynamic code execution library
|
|
4
|
+
*
|
|
5
|
+
* Provides secure execution of dynamic JavaScript code using new Function()
|
|
6
|
+
* with configurable security policies and sandboxing capabilities.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const loader = new DynaJs({
|
|
11
|
+
* defaultImports: { MyClass },
|
|
12
|
+
* validateCode: true,
|
|
13
|
+
* allowBrowserAPIs: false
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* const result = loader.executeSync(`return new MyClass()`);
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
2
19
|
export default class DynaJs {
|
|
3
20
|
private config;
|
|
21
|
+
/**
|
|
22
|
+
* Creates a new DynaJs instance
|
|
23
|
+
*
|
|
24
|
+
* @param config - Configuration options for the DynaJs instance
|
|
25
|
+
* @param config.defaultTimeout - Default timeout for async execution in milliseconds (default: 5000)
|
|
26
|
+
* @param config.defaultStrict - Whether to use strict mode by default (default: true)
|
|
27
|
+
* @param config.allowedGlobals - Whitelist of allowed global variables (empty = allow all defaultImports)
|
|
28
|
+
* @param config.blockedGlobals - Blacklist of blocked global variables
|
|
29
|
+
* @param config.defaultImports - Pre-imported classes/functions available to dynamic code
|
|
30
|
+
* @param config.allowTimers - Allow setTimeout/setInterval in dynamic code (default: false)
|
|
31
|
+
* @param config.allowDynamicImports - Allow import()/require() in dynamic code (default: false)
|
|
32
|
+
* @param config.validateCode - Enable code validation before execution (default: true)
|
|
33
|
+
* @param config.allowBrowserAPIs - Allow access to browser APIs like window/document (default: false)
|
|
34
|
+
* @param config.allowNodeAPIs - Allow access to Node.js APIs like process/require (default: false)
|
|
35
|
+
*/
|
|
4
36
|
constructor(config?: DynaJsConfig);
|
|
5
|
-
|
|
6
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Asynchronously execute dynamic code with timeout support
|
|
39
|
+
*
|
|
40
|
+
* @template T - The expected return type of the executed code
|
|
41
|
+
* @param code - The JavaScript code to execute
|
|
42
|
+
* @param options - Execution options
|
|
43
|
+
* @param options.context - Additional context variables for the code
|
|
44
|
+
* @param options.timeout - Execution timeout in milliseconds (overrides defaultTimeout)
|
|
45
|
+
* @param options.strict - Whether to use strict mode (overrides defaultStrict)
|
|
46
|
+
* @param options.imports - Additional imports for this execution only
|
|
47
|
+
* @returns Promise resolving to the execution result
|
|
48
|
+
*/
|
|
49
|
+
execute<T = any>(code: string, options?: ExecutionOptions): Promise<T>;
|
|
50
|
+
/**
|
|
51
|
+
* Synchronously execute dynamic code and return result directly
|
|
52
|
+
*
|
|
53
|
+
* @template T - The expected return type of the executed code
|
|
54
|
+
* @param code - The JavaScript code to execute
|
|
55
|
+
* @param options - Execution options
|
|
56
|
+
* @param options.context - Additional context variables for the code
|
|
57
|
+
* @param options.strict - Whether to use strict mode (overrides defaultStrict)
|
|
58
|
+
* @param options.imports - Additional imports for this execution only
|
|
59
|
+
* @returns The direct result of code execution
|
|
60
|
+
*/
|
|
61
|
+
executeSync<T = any>(code: string, options?: ExecutionOptions): T;
|
|
62
|
+
/**
|
|
63
|
+
* Execute code with a timeout constraint
|
|
64
|
+
*
|
|
65
|
+
* @private
|
|
66
|
+
* @template T - The expected return type
|
|
67
|
+
* @param code - The JavaScript code to execute
|
|
68
|
+
* @param context - Execution context with available variables
|
|
69
|
+
* @param timeout - Maximum execution time in milliseconds
|
|
70
|
+
* @param strict - Whether to use strict mode
|
|
71
|
+
* @returns Promise resolving to the execution result
|
|
72
|
+
* @throws {Error} If execution exceeds timeout or runtime error occurs
|
|
73
|
+
*/
|
|
7
74
|
private executeWithTimeout;
|
|
75
|
+
/**
|
|
76
|
+
* Core code execution engine using new Function()
|
|
77
|
+
*
|
|
78
|
+
* @private
|
|
79
|
+
* @param code - The JavaScript code to execute
|
|
80
|
+
* @param context - Execution context with available variables
|
|
81
|
+
* @param strict - Whether to use strict mode
|
|
82
|
+
* @returns The execution result
|
|
83
|
+
* @throws {Error} If code execution fails
|
|
84
|
+
*/
|
|
8
85
|
private executeCode;
|
|
86
|
+
/**
|
|
87
|
+
* Create a reusable function from dynamic code
|
|
88
|
+
*
|
|
89
|
+
* @template T - The function signature type
|
|
90
|
+
* @param code - The JavaScript code for the function body
|
|
91
|
+
* @param paramNames - Array of parameter names for the function
|
|
92
|
+
* @param options - Execution options
|
|
93
|
+
* @param options.context - Additional context variables
|
|
94
|
+
* @param options.strict - Whether to use strict mode
|
|
95
|
+
* @param options.imports - Additional imports
|
|
96
|
+
* @returns A function that can be called multiple times
|
|
97
|
+
* @throws {Error} If function creation fails
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* const validator = loader.createFunction<(data: any) => boolean>(`
|
|
102
|
+
* return function(data) {
|
|
103
|
+
* return data.name && data.email;
|
|
104
|
+
* };
|
|
105
|
+
* `);
|
|
106
|
+
* const isValid = validator({ name: 'John', email: 'john@example.com' });
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
9
109
|
createFunction<T extends (...args: any[]) => any>(code: string, paramNames?: string[], options?: ExecutionOptions): T;
|
|
10
|
-
|
|
11
|
-
|
|
110
|
+
/**
|
|
111
|
+
* Synchronously execute code with additional temporary imports
|
|
112
|
+
*
|
|
113
|
+
* @template T - The expected return type
|
|
114
|
+
* @param code - The JavaScript code to execute
|
|
115
|
+
* @param imports - Additional imports to merge with defaultImports
|
|
116
|
+
* @param options - Additional execution options
|
|
117
|
+
* @returns The direct result of code execution
|
|
118
|
+
* @throws {Error} If code validation fails or runtime error occurs
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* const result = loader.executeWithImports(`
|
|
123
|
+
* return new CustomComponent();
|
|
124
|
+
* `, {
|
|
125
|
+
* CustomComponent: MyCustomComponent
|
|
126
|
+
* });
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
executeWithImports<T = any>(code: string, imports: ModuleImports, options?: ExecutionOptions): T;
|
|
130
|
+
/**
|
|
131
|
+
* Asynchronously execute code with additional temporary imports
|
|
132
|
+
*
|
|
133
|
+
* @template T - The expected return type
|
|
134
|
+
* @param code - The JavaScript code to execute
|
|
135
|
+
* @param imports - Additional imports to merge with defaultImports
|
|
136
|
+
* @param options - Additional execution options (including timeout)
|
|
137
|
+
* @returns Promise resolving to the execution result
|
|
138
|
+
* @throws {Error} If code validation fails, execution times out, or runtime error occurs
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* const result = await loader.executeWithImportsAsync(`
|
|
143
|
+
* return await fetchData();
|
|
144
|
+
* `, {
|
|
145
|
+
* fetchData: myFetchFunction
|
|
146
|
+
* }, { timeout: 5000 });
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
executeWithImportsAsync<T = any>(code: string, imports: ModuleImports, options?: ExecutionOptions): Promise<T>;
|
|
150
|
+
/**
|
|
151
|
+
* Singleton instance of DynaJs
|
|
152
|
+
* @private
|
|
153
|
+
*/
|
|
12
154
|
static instance: DynaJs | null;
|
|
155
|
+
/**
|
|
156
|
+
* Initialize the singleton instance of DynaJs
|
|
157
|
+
*
|
|
158
|
+
* @param config - Configuration options for the singleton instance
|
|
159
|
+
* @returns The initialized singleton instance
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```typescript
|
|
163
|
+
* DynaJs.initialize({
|
|
164
|
+
* defaultImports: { MyClass, MyFunction },
|
|
165
|
+
* validateCode: true
|
|
166
|
+
* });
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
13
169
|
static initialize(config: DynaJsConfig): DynaJs;
|
|
170
|
+
/**
|
|
171
|
+
* Get the singleton instance of DynaJs
|
|
172
|
+
*
|
|
173
|
+
* @returns The singleton instance
|
|
174
|
+
* @throws {Error} If DynaJs hasn't been initialized
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* const loader = DynaJs.getInstance();
|
|
179
|
+
* const result = loader.executeSync(`return 1 + 1`);
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
14
182
|
static getInstance(): DynaJs;
|
|
183
|
+
/**
|
|
184
|
+
* Reset the singleton instance (useful for testing)
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```typescript
|
|
188
|
+
* DynaJs.reset();
|
|
189
|
+
* DynaJs.initialize(newConfig);
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
15
192
|
static reset(): void;
|
|
193
|
+
/**
|
|
194
|
+
* Prepare the execution context by merging user context, imports, and applying security filters
|
|
195
|
+
*
|
|
196
|
+
* Execution flow:
|
|
197
|
+
* 1. Create safe context (filtering browser/node APIs based on config)
|
|
198
|
+
* 2. Merge with defaultImports and additional imports
|
|
199
|
+
* 3. Apply allowedGlobals whitelist filter if configured
|
|
200
|
+
*
|
|
201
|
+
* @private
|
|
202
|
+
* @param userContext - User-provided context variables
|
|
203
|
+
* @param imports - Additional imports for this execution
|
|
204
|
+
* @returns The final execution context
|
|
205
|
+
*
|
|
206
|
+
* @remarks
|
|
207
|
+
* If allowedGlobals is set and not empty, only variables in the whitelist will be available.
|
|
208
|
+
* This happens AFTER merging defaultImports, so make sure to include all needed imports
|
|
209
|
+
* in the allowedGlobals array if you use this feature.
|
|
210
|
+
*/
|
|
16
211
|
private prepareContext;
|
|
17
212
|
}
|
|
18
213
|
//# sourceMappingURL=DynaJs.d.ts.map
|
package/dist/DynaJs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DynaJs.d.ts","sourceRoot":"","sources":["../src/DynaJs.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"DynaJs.d.ts","sourceRoot":"","sources":["../src/DynaJs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,gBAAgB,EAAE,YAAY,EAAE,aAAa,EAAC,MAAM,SAAS,CAAC;AAGxF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,OAAO,OAAO,MAAM;IACvB,OAAO,CAAC,MAAM,CAAyB;IAEvC;;;;;;;;;;;;;;OAcG;gBACS,MAAM,GAAE,YAAiB;IAerC;;;;;;;;;;;OAWG;IACG,OAAO,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,CAAC,CAAC;IAwBhF;;;;;;;;;;OAUG;IACH,WAAW,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,CAAC;IAuBrE;;;;;;;;;;;OAWG;YACW,kBAAkB;IAiBhC;;;;;;;;;OASG;IACH,OAAO,CAAC,WAAW;IAenB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,cAAc,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAC5C,IAAI,EAAE,MAAM,EACZ,UAAU,GAAE,MAAM,EAAO,EACzB,OAAO,GAAE,gBAAqB,GAC/B,CAAC;IAuBJ;;;;;;;;;;;;;;;;;;OAkBG;IACH,kBAAkB,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,GAAE,gBAAqB,GAAG,CAAC;IAOpG;;;;;;;;;;;;;;;;;;OAkBG;IACG,uBAAuB,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,CAAC,CAAC;IAOxH;;;OAGG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEtC;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM;IAO/C;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,WAAW,IAAI,MAAM;IAO5B;;;;;;;;OAQG;IACH,MAAM,CAAC,KAAK,IAAI,IAAI;IAIpB;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,cAAc;CAwBzB"}
|
package/dist/DynaJs.esm.js
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
import { createSafeContext, validateCode } from './utils';
|
|
2
|
+
/**
|
|
3
|
+
* DynaJs - A safe dynamic code execution library
|
|
4
|
+
*
|
|
5
|
+
* Provides secure execution of dynamic JavaScript code using new Function()
|
|
6
|
+
* with configurable security policies and sandboxing capabilities.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const loader = new DynaJs({
|
|
11
|
+
* defaultImports: { MyClass },
|
|
12
|
+
* validateCode: true,
|
|
13
|
+
* allowBrowserAPIs: false
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* const result = loader.executeSync(`return new MyClass()`);
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
2
19
|
class DynaJs {
|
|
20
|
+
/**
|
|
21
|
+
* Creates a new DynaJs instance
|
|
22
|
+
*
|
|
23
|
+
* @param config - Configuration options for the DynaJs instance
|
|
24
|
+
* @param config.defaultTimeout - Default timeout for async execution in milliseconds (default: 5000)
|
|
25
|
+
* @param config.defaultStrict - Whether to use strict mode by default (default: true)
|
|
26
|
+
* @param config.allowedGlobals - Whitelist of allowed global variables (empty = allow all defaultImports)
|
|
27
|
+
* @param config.blockedGlobals - Blacklist of blocked global variables
|
|
28
|
+
* @param config.defaultImports - Pre-imported classes/functions available to dynamic code
|
|
29
|
+
* @param config.allowTimers - Allow setTimeout/setInterval in dynamic code (default: false)
|
|
30
|
+
* @param config.allowDynamicImports - Allow import()/require() in dynamic code (default: false)
|
|
31
|
+
* @param config.validateCode - Enable code validation before execution (default: true)
|
|
32
|
+
* @param config.allowBrowserAPIs - Allow access to browser APIs like window/document (default: false)
|
|
33
|
+
* @param config.allowNodeAPIs - Allow access to Node.js APIs like process/require (default: false)
|
|
34
|
+
*/
|
|
3
35
|
constructor(config = {}) {
|
|
4
36
|
this.config = {
|
|
5
37
|
defaultTimeout: config.defaultTimeout ?? 5000,
|
|
@@ -14,6 +46,18 @@ class DynaJs {
|
|
|
14
46
|
allowNodeAPIs: config.allowNodeAPIs ?? false
|
|
15
47
|
};
|
|
16
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Asynchronously execute dynamic code with timeout support
|
|
51
|
+
*
|
|
52
|
+
* @template T - The expected return type of the executed code
|
|
53
|
+
* @param code - The JavaScript code to execute
|
|
54
|
+
* @param options - Execution options
|
|
55
|
+
* @param options.context - Additional context variables for the code
|
|
56
|
+
* @param options.timeout - Execution timeout in milliseconds (overrides defaultTimeout)
|
|
57
|
+
* @param options.strict - Whether to use strict mode (overrides defaultStrict)
|
|
58
|
+
* @param options.imports - Additional imports for this execution only
|
|
59
|
+
* @returns Promise resolving to the execution result
|
|
60
|
+
*/
|
|
17
61
|
async execute(code, options = {}) {
|
|
18
62
|
const startTime = performance.now();
|
|
19
63
|
try {
|
|
@@ -27,17 +71,25 @@ class DynaJs {
|
|
|
27
71
|
const timeout = options.timeout ?? this.config.defaultTimeout;
|
|
28
72
|
const strict = options.strict ?? this.config.defaultStrict;
|
|
29
73
|
const result = await this.executeWithTimeout(code, context, timeout, strict);
|
|
30
|
-
|
|
31
|
-
return
|
|
32
|
-
result: result,
|
|
33
|
-
executionTime
|
|
34
|
-
};
|
|
74
|
+
console.info(`Build dyna code in ${performance.now() - startTime}ms`);
|
|
75
|
+
return result;
|
|
35
76
|
}
|
|
36
77
|
catch (error) {
|
|
37
78
|
const executionTime = performance.now() - startTime;
|
|
38
79
|
throw new Error(`Script execution failed after ${executionTime.toFixed(2)}ms: ${error instanceof Error ? error.message : String(error)}`);
|
|
39
80
|
}
|
|
40
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Synchronously execute dynamic code and return result directly
|
|
84
|
+
*
|
|
85
|
+
* @template T - The expected return type of the executed code
|
|
86
|
+
* @param code - The JavaScript code to execute
|
|
87
|
+
* @param options - Execution options
|
|
88
|
+
* @param options.context - Additional context variables for the code
|
|
89
|
+
* @param options.strict - Whether to use strict mode (overrides defaultStrict)
|
|
90
|
+
* @param options.imports - Additional imports for this execution only
|
|
91
|
+
* @returns The direct result of code execution
|
|
92
|
+
*/
|
|
41
93
|
executeSync(code, options = {}) {
|
|
42
94
|
const startTime = performance.now();
|
|
43
95
|
try {
|
|
@@ -50,17 +102,26 @@ class DynaJs {
|
|
|
50
102
|
const context = this.prepareContext(options.context, options.imports);
|
|
51
103
|
const strict = options.strict ?? this.config.defaultStrict;
|
|
52
104
|
const result = this.executeCode(code, context, strict);
|
|
53
|
-
|
|
54
|
-
return
|
|
55
|
-
result: result,
|
|
56
|
-
executionTime
|
|
57
|
-
};
|
|
105
|
+
console.info(`Build dyna code in ${performance.now() - startTime}ms`);
|
|
106
|
+
return result;
|
|
58
107
|
}
|
|
59
108
|
catch (error) {
|
|
60
109
|
const executionTime = performance.now() - startTime;
|
|
61
110
|
throw new Error(`Script execution failed after ${executionTime.toFixed(2)}ms: ${error instanceof Error ? error.message : String(error)}`);
|
|
62
111
|
}
|
|
63
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Execute code with a timeout constraint
|
|
115
|
+
*
|
|
116
|
+
* @private
|
|
117
|
+
* @template T - The expected return type
|
|
118
|
+
* @param code - The JavaScript code to execute
|
|
119
|
+
* @param context - Execution context with available variables
|
|
120
|
+
* @param timeout - Maximum execution time in milliseconds
|
|
121
|
+
* @param strict - Whether to use strict mode
|
|
122
|
+
* @returns Promise resolving to the execution result
|
|
123
|
+
* @throws {Error} If execution exceeds timeout or runtime error occurs
|
|
124
|
+
*/
|
|
64
125
|
async executeWithTimeout(code, context, timeout, strict) {
|
|
65
126
|
return new Promise((resolve, reject) => {
|
|
66
127
|
const timer = setTimeout(() => {
|
|
@@ -77,6 +138,16 @@ class DynaJs {
|
|
|
77
138
|
}
|
|
78
139
|
});
|
|
79
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Core code execution engine using new Function()
|
|
143
|
+
*
|
|
144
|
+
* @private
|
|
145
|
+
* @param code - The JavaScript code to execute
|
|
146
|
+
* @param context - Execution context with available variables
|
|
147
|
+
* @param strict - Whether to use strict mode
|
|
148
|
+
* @returns The execution result
|
|
149
|
+
* @throws {Error} If code execution fails
|
|
150
|
+
*/
|
|
80
151
|
executeCode(code, context, strict) {
|
|
81
152
|
const contextKeys = Object.keys(context);
|
|
82
153
|
const contextValues = Object.values(context);
|
|
@@ -90,6 +161,29 @@ class DynaJs {
|
|
|
90
161
|
throw new Error(`Code execution error: ${error instanceof Error ? error.message : String(error)}`);
|
|
91
162
|
}
|
|
92
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Create a reusable function from dynamic code
|
|
166
|
+
*
|
|
167
|
+
* @template T - The function signature type
|
|
168
|
+
* @param code - The JavaScript code for the function body
|
|
169
|
+
* @param paramNames - Array of parameter names for the function
|
|
170
|
+
* @param options - Execution options
|
|
171
|
+
* @param options.context - Additional context variables
|
|
172
|
+
* @param options.strict - Whether to use strict mode
|
|
173
|
+
* @param options.imports - Additional imports
|
|
174
|
+
* @returns A function that can be called multiple times
|
|
175
|
+
* @throws {Error} If function creation fails
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* const validator = loader.createFunction<(data: any) => boolean>(`
|
|
180
|
+
* return function(data) {
|
|
181
|
+
* return data.name && data.email;
|
|
182
|
+
* };
|
|
183
|
+
* `);
|
|
184
|
+
* const isValid = validator({ name: 'John', email: 'john@example.com' });
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
93
187
|
createFunction(code, paramNames = [], options = {}) {
|
|
94
188
|
const context = this.prepareContext(options.context, options.imports);
|
|
95
189
|
const strict = options.strict ?? this.config.defaultStrict;
|
|
@@ -109,33 +203,124 @@ class DynaJs {
|
|
|
109
203
|
throw new Error(`Function creation error: ${error instanceof Error ? error.message : String(error)}`);
|
|
110
204
|
}
|
|
111
205
|
}
|
|
206
|
+
/**
|
|
207
|
+
* Synchronously execute code with additional temporary imports
|
|
208
|
+
*
|
|
209
|
+
* @template T - The expected return type
|
|
210
|
+
* @param code - The JavaScript code to execute
|
|
211
|
+
* @param imports - Additional imports to merge with defaultImports
|
|
212
|
+
* @param options - Additional execution options
|
|
213
|
+
* @returns The direct result of code execution
|
|
214
|
+
* @throws {Error} If code validation fails or runtime error occurs
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* const result = loader.executeWithImports(`
|
|
219
|
+
* return new CustomComponent();
|
|
220
|
+
* `, {
|
|
221
|
+
* CustomComponent: MyCustomComponent
|
|
222
|
+
* });
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
112
225
|
executeWithImports(code, imports, options = {}) {
|
|
113
226
|
return this.executeSync(code, {
|
|
114
227
|
...options,
|
|
115
228
|
imports: { ...this.config.defaultImports, ...imports }
|
|
116
229
|
});
|
|
117
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* Asynchronously execute code with additional temporary imports
|
|
233
|
+
*
|
|
234
|
+
* @template T - The expected return type
|
|
235
|
+
* @param code - The JavaScript code to execute
|
|
236
|
+
* @param imports - Additional imports to merge with defaultImports
|
|
237
|
+
* @param options - Additional execution options (including timeout)
|
|
238
|
+
* @returns Promise resolving to the execution result
|
|
239
|
+
* @throws {Error} If code validation fails, execution times out, or runtime error occurs
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```typescript
|
|
243
|
+
* const result = await loader.executeWithImportsAsync(`
|
|
244
|
+
* return await fetchData();
|
|
245
|
+
* `, {
|
|
246
|
+
* fetchData: myFetchFunction
|
|
247
|
+
* }, { timeout: 5000 });
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
118
250
|
async executeWithImportsAsync(code, imports, options = {}) {
|
|
119
251
|
return this.execute(code, {
|
|
120
252
|
...options,
|
|
121
253
|
imports: { ...this.config.defaultImports, ...imports }
|
|
122
254
|
});
|
|
123
255
|
}
|
|
256
|
+
/**
|
|
257
|
+
* Initialize the singleton instance of DynaJs
|
|
258
|
+
*
|
|
259
|
+
* @param config - Configuration options for the singleton instance
|
|
260
|
+
* @returns The initialized singleton instance
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* ```typescript
|
|
264
|
+
* DynaJs.initialize({
|
|
265
|
+
* defaultImports: { MyClass, MyFunction },
|
|
266
|
+
* validateCode: true
|
|
267
|
+
* });
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
124
270
|
static initialize(config) {
|
|
125
271
|
if (DynaJs.instance == null) {
|
|
126
272
|
DynaJs.instance = new DynaJs(config);
|
|
127
273
|
}
|
|
128
274
|
return DynaJs.instance;
|
|
129
275
|
}
|
|
276
|
+
/**
|
|
277
|
+
* Get the singleton instance of DynaJs
|
|
278
|
+
*
|
|
279
|
+
* @returns The singleton instance
|
|
280
|
+
* @throws {Error} If DynaJs hasn't been initialized
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```typescript
|
|
284
|
+
* const loader = DynaJs.getInstance();
|
|
285
|
+
* const result = loader.executeSync(`return 1 + 1`);
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
130
288
|
static getInstance() {
|
|
131
289
|
if (DynaJs.instance == null) {
|
|
132
290
|
throw new Error("DynaJs hasn't been initialized. Call DynaJs.initialize() first.");
|
|
133
291
|
}
|
|
134
292
|
return DynaJs.instance;
|
|
135
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* Reset the singleton instance (useful for testing)
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* ```typescript
|
|
299
|
+
* DynaJs.reset();
|
|
300
|
+
* DynaJs.initialize(newConfig);
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
136
303
|
static reset() {
|
|
137
304
|
DynaJs.instance = null;
|
|
138
305
|
}
|
|
306
|
+
/**
|
|
307
|
+
* Prepare the execution context by merging user context, imports, and applying security filters
|
|
308
|
+
*
|
|
309
|
+
* Execution flow:
|
|
310
|
+
* 1. Create safe context (filtering browser/node APIs based on config)
|
|
311
|
+
* 2. Merge with defaultImports and additional imports
|
|
312
|
+
* 3. Apply allowedGlobals whitelist filter if configured
|
|
313
|
+
*
|
|
314
|
+
* @private
|
|
315
|
+
* @param userContext - User-provided context variables
|
|
316
|
+
* @param imports - Additional imports for this execution
|
|
317
|
+
* @returns The final execution context
|
|
318
|
+
*
|
|
319
|
+
* @remarks
|
|
320
|
+
* If allowedGlobals is set and not empty, only variables in the whitelist will be available.
|
|
321
|
+
* This happens AFTER merging defaultImports, so make sure to include all needed imports
|
|
322
|
+
* in the allowedGlobals array if you use this feature.
|
|
323
|
+
*/
|
|
139
324
|
prepareContext(userContext = {}, imports = {}) {
|
|
140
325
|
let context = createSafeContext(userContext, {
|
|
141
326
|
allowBrowserAPIs: this.config.allowBrowserAPIs,
|
|
@@ -155,5 +340,9 @@ class DynaJs {
|
|
|
155
340
|
return context;
|
|
156
341
|
}
|
|
157
342
|
}
|
|
343
|
+
/**
|
|
344
|
+
* Singleton instance of DynaJs
|
|
345
|
+
* @private
|
|
346
|
+
*/
|
|
158
347
|
DynaJs.instance = null;
|
|
159
348
|
export default DynaJs;
|
package/dist/DynaJs.js
CHANGED
|
@@ -1,7 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const utils_1 = require("./utils");
|
|
4
|
+
/**
|
|
5
|
+
* DynaJs - A safe dynamic code execution library
|
|
6
|
+
*
|
|
7
|
+
* Provides secure execution of dynamic JavaScript code using new Function()
|
|
8
|
+
* with configurable security policies and sandboxing capabilities.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const loader = new DynaJs({
|
|
13
|
+
* defaultImports: { MyClass },
|
|
14
|
+
* validateCode: true,
|
|
15
|
+
* allowBrowserAPIs: false
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* const result = loader.executeSync(`return new MyClass()`);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
4
21
|
class DynaJs {
|
|
22
|
+
/**
|
|
23
|
+
* Creates a new DynaJs instance
|
|
24
|
+
*
|
|
25
|
+
* @param config - Configuration options for the DynaJs instance
|
|
26
|
+
* @param config.defaultTimeout - Default timeout for async execution in milliseconds (default: 5000)
|
|
27
|
+
* @param config.defaultStrict - Whether to use strict mode by default (default: true)
|
|
28
|
+
* @param config.allowedGlobals - Whitelist of allowed global variables (empty = allow all defaultImports)
|
|
29
|
+
* @param config.blockedGlobals - Blacklist of blocked global variables
|
|
30
|
+
* @param config.defaultImports - Pre-imported classes/functions available to dynamic code
|
|
31
|
+
* @param config.allowTimers - Allow setTimeout/setInterval in dynamic code (default: false)
|
|
32
|
+
* @param config.allowDynamicImports - Allow import()/require() in dynamic code (default: false)
|
|
33
|
+
* @param config.validateCode - Enable code validation before execution (default: true)
|
|
34
|
+
* @param config.allowBrowserAPIs - Allow access to browser APIs like window/document (default: false)
|
|
35
|
+
* @param config.allowNodeAPIs - Allow access to Node.js APIs like process/require (default: false)
|
|
36
|
+
*/
|
|
5
37
|
constructor(config = {}) {
|
|
6
38
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
7
39
|
this.config = {
|
|
@@ -17,6 +49,18 @@ class DynaJs {
|
|
|
17
49
|
allowNodeAPIs: (_k = config.allowNodeAPIs) !== null && _k !== void 0 ? _k : false
|
|
18
50
|
};
|
|
19
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Asynchronously execute dynamic code with timeout support
|
|
54
|
+
*
|
|
55
|
+
* @template T - The expected return type of the executed code
|
|
56
|
+
* @param code - The JavaScript code to execute
|
|
57
|
+
* @param options - Execution options
|
|
58
|
+
* @param options.context - Additional context variables for the code
|
|
59
|
+
* @param options.timeout - Execution timeout in milliseconds (overrides defaultTimeout)
|
|
60
|
+
* @param options.strict - Whether to use strict mode (overrides defaultStrict)
|
|
61
|
+
* @param options.imports - Additional imports for this execution only
|
|
62
|
+
* @returns Promise resolving to the execution result
|
|
63
|
+
*/
|
|
20
64
|
async execute(code, options = {}) {
|
|
21
65
|
var _a, _b;
|
|
22
66
|
const startTime = performance.now();
|
|
@@ -31,17 +75,25 @@ class DynaJs {
|
|
|
31
75
|
const timeout = (_a = options.timeout) !== null && _a !== void 0 ? _a : this.config.defaultTimeout;
|
|
32
76
|
const strict = (_b = options.strict) !== null && _b !== void 0 ? _b : this.config.defaultStrict;
|
|
33
77
|
const result = await this.executeWithTimeout(code, context, timeout, strict);
|
|
34
|
-
|
|
35
|
-
return
|
|
36
|
-
result: result,
|
|
37
|
-
executionTime
|
|
38
|
-
};
|
|
78
|
+
console.info(`Build dyna code in ${performance.now() - startTime}ms`);
|
|
79
|
+
return result;
|
|
39
80
|
}
|
|
40
81
|
catch (error) {
|
|
41
82
|
const executionTime = performance.now() - startTime;
|
|
42
83
|
throw new Error(`Script execution failed after ${executionTime.toFixed(2)}ms: ${error instanceof Error ? error.message : String(error)}`);
|
|
43
84
|
}
|
|
44
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Synchronously execute dynamic code and return result directly
|
|
88
|
+
*
|
|
89
|
+
* @template T - The expected return type of the executed code
|
|
90
|
+
* @param code - The JavaScript code to execute
|
|
91
|
+
* @param options - Execution options
|
|
92
|
+
* @param options.context - Additional context variables for the code
|
|
93
|
+
* @param options.strict - Whether to use strict mode (overrides defaultStrict)
|
|
94
|
+
* @param options.imports - Additional imports for this execution only
|
|
95
|
+
* @returns The direct result of code execution
|
|
96
|
+
*/
|
|
45
97
|
executeSync(code, options = {}) {
|
|
46
98
|
var _a;
|
|
47
99
|
const startTime = performance.now();
|
|
@@ -55,17 +107,26 @@ class DynaJs {
|
|
|
55
107
|
const context = this.prepareContext(options.context, options.imports);
|
|
56
108
|
const strict = (_a = options.strict) !== null && _a !== void 0 ? _a : this.config.defaultStrict;
|
|
57
109
|
const result = this.executeCode(code, context, strict);
|
|
58
|
-
|
|
59
|
-
return
|
|
60
|
-
result: result,
|
|
61
|
-
executionTime
|
|
62
|
-
};
|
|
110
|
+
console.info(`Build dyna code in ${performance.now() - startTime}ms`);
|
|
111
|
+
return result;
|
|
63
112
|
}
|
|
64
113
|
catch (error) {
|
|
65
114
|
const executionTime = performance.now() - startTime;
|
|
66
115
|
throw new Error(`Script execution failed after ${executionTime.toFixed(2)}ms: ${error instanceof Error ? error.message : String(error)}`);
|
|
67
116
|
}
|
|
68
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Execute code with a timeout constraint
|
|
120
|
+
*
|
|
121
|
+
* @private
|
|
122
|
+
* @template T - The expected return type
|
|
123
|
+
* @param code - The JavaScript code to execute
|
|
124
|
+
* @param context - Execution context with available variables
|
|
125
|
+
* @param timeout - Maximum execution time in milliseconds
|
|
126
|
+
* @param strict - Whether to use strict mode
|
|
127
|
+
* @returns Promise resolving to the execution result
|
|
128
|
+
* @throws {Error} If execution exceeds timeout or runtime error occurs
|
|
129
|
+
*/
|
|
69
130
|
async executeWithTimeout(code, context, timeout, strict) {
|
|
70
131
|
return new Promise((resolve, reject) => {
|
|
71
132
|
const timer = setTimeout(() => {
|
|
@@ -82,6 +143,16 @@ class DynaJs {
|
|
|
82
143
|
}
|
|
83
144
|
});
|
|
84
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Core code execution engine using new Function()
|
|
148
|
+
*
|
|
149
|
+
* @private
|
|
150
|
+
* @param code - The JavaScript code to execute
|
|
151
|
+
* @param context - Execution context with available variables
|
|
152
|
+
* @param strict - Whether to use strict mode
|
|
153
|
+
* @returns The execution result
|
|
154
|
+
* @throws {Error} If code execution fails
|
|
155
|
+
*/
|
|
85
156
|
executeCode(code, context, strict) {
|
|
86
157
|
const contextKeys = Object.keys(context);
|
|
87
158
|
const contextValues = Object.values(context);
|
|
@@ -95,6 +166,29 @@ class DynaJs {
|
|
|
95
166
|
throw new Error(`Code execution error: ${error instanceof Error ? error.message : String(error)}`);
|
|
96
167
|
}
|
|
97
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* Create a reusable function from dynamic code
|
|
171
|
+
*
|
|
172
|
+
* @template T - The function signature type
|
|
173
|
+
* @param code - The JavaScript code for the function body
|
|
174
|
+
* @param paramNames - Array of parameter names for the function
|
|
175
|
+
* @param options - Execution options
|
|
176
|
+
* @param options.context - Additional context variables
|
|
177
|
+
* @param options.strict - Whether to use strict mode
|
|
178
|
+
* @param options.imports - Additional imports
|
|
179
|
+
* @returns A function that can be called multiple times
|
|
180
|
+
* @throws {Error} If function creation fails
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const validator = loader.createFunction<(data: any) => boolean>(`
|
|
185
|
+
* return function(data) {
|
|
186
|
+
* return data.name && data.email;
|
|
187
|
+
* };
|
|
188
|
+
* `);
|
|
189
|
+
* const isValid = validator({ name: 'John', email: 'john@example.com' });
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
98
192
|
createFunction(code, paramNames = [], options = {}) {
|
|
99
193
|
var _a;
|
|
100
194
|
const context = this.prepareContext(options.context, options.imports);
|
|
@@ -115,27 +209,118 @@ class DynaJs {
|
|
|
115
209
|
throw new Error(`Function creation error: ${error instanceof Error ? error.message : String(error)}`);
|
|
116
210
|
}
|
|
117
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* Synchronously execute code with additional temporary imports
|
|
214
|
+
*
|
|
215
|
+
* @template T - The expected return type
|
|
216
|
+
* @param code - The JavaScript code to execute
|
|
217
|
+
* @param imports - Additional imports to merge with defaultImports
|
|
218
|
+
* @param options - Additional execution options
|
|
219
|
+
* @returns The direct result of code execution
|
|
220
|
+
* @throws {Error} If code validation fails or runtime error occurs
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* const result = loader.executeWithImports(`
|
|
225
|
+
* return new CustomComponent();
|
|
226
|
+
* `, {
|
|
227
|
+
* CustomComponent: MyCustomComponent
|
|
228
|
+
* });
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
118
231
|
executeWithImports(code, imports, options = {}) {
|
|
119
232
|
return this.executeSync(code, Object.assign(Object.assign({}, options), { imports: Object.assign(Object.assign({}, this.config.defaultImports), imports) }));
|
|
120
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* Asynchronously execute code with additional temporary imports
|
|
236
|
+
*
|
|
237
|
+
* @template T - The expected return type
|
|
238
|
+
* @param code - The JavaScript code to execute
|
|
239
|
+
* @param imports - Additional imports to merge with defaultImports
|
|
240
|
+
* @param options - Additional execution options (including timeout)
|
|
241
|
+
* @returns Promise resolving to the execution result
|
|
242
|
+
* @throws {Error} If code validation fails, execution times out, or runtime error occurs
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```typescript
|
|
246
|
+
* const result = await loader.executeWithImportsAsync(`
|
|
247
|
+
* return await fetchData();
|
|
248
|
+
* `, {
|
|
249
|
+
* fetchData: myFetchFunction
|
|
250
|
+
* }, { timeout: 5000 });
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
121
253
|
async executeWithImportsAsync(code, imports, options = {}) {
|
|
122
254
|
return this.execute(code, Object.assign(Object.assign({}, options), { imports: Object.assign(Object.assign({}, this.config.defaultImports), imports) }));
|
|
123
255
|
}
|
|
256
|
+
/**
|
|
257
|
+
* Initialize the singleton instance of DynaJs
|
|
258
|
+
*
|
|
259
|
+
* @param config - Configuration options for the singleton instance
|
|
260
|
+
* @returns The initialized singleton instance
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* ```typescript
|
|
264
|
+
* DynaJs.initialize({
|
|
265
|
+
* defaultImports: { MyClass, MyFunction },
|
|
266
|
+
* validateCode: true
|
|
267
|
+
* });
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
124
270
|
static initialize(config) {
|
|
125
271
|
if (DynaJs.instance == null) {
|
|
126
272
|
DynaJs.instance = new DynaJs(config);
|
|
127
273
|
}
|
|
128
274
|
return DynaJs.instance;
|
|
129
275
|
}
|
|
276
|
+
/**
|
|
277
|
+
* Get the singleton instance of DynaJs
|
|
278
|
+
*
|
|
279
|
+
* @returns The singleton instance
|
|
280
|
+
* @throws {Error} If DynaJs hasn't been initialized
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```typescript
|
|
284
|
+
* const loader = DynaJs.getInstance();
|
|
285
|
+
* const result = loader.executeSync(`return 1 + 1`);
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
130
288
|
static getInstance() {
|
|
131
289
|
if (DynaJs.instance == null) {
|
|
132
290
|
throw new Error("DynaJs hasn't been initialized. Call DynaJs.initialize() first.");
|
|
133
291
|
}
|
|
134
292
|
return DynaJs.instance;
|
|
135
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* Reset the singleton instance (useful for testing)
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* ```typescript
|
|
299
|
+
* DynaJs.reset();
|
|
300
|
+
* DynaJs.initialize(newConfig);
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
136
303
|
static reset() {
|
|
137
304
|
DynaJs.instance = null;
|
|
138
305
|
}
|
|
306
|
+
/**
|
|
307
|
+
* Prepare the execution context by merging user context, imports, and applying security filters
|
|
308
|
+
*
|
|
309
|
+
* Execution flow:
|
|
310
|
+
* 1. Create safe context (filtering browser/node APIs based on config)
|
|
311
|
+
* 2. Merge with defaultImports and additional imports
|
|
312
|
+
* 3. Apply allowedGlobals whitelist filter if configured
|
|
313
|
+
*
|
|
314
|
+
* @private
|
|
315
|
+
* @param userContext - User-provided context variables
|
|
316
|
+
* @param imports - Additional imports for this execution
|
|
317
|
+
* @returns The final execution context
|
|
318
|
+
*
|
|
319
|
+
* @remarks
|
|
320
|
+
* If allowedGlobals is set and not empty, only variables in the whitelist will be available.
|
|
321
|
+
* This happens AFTER merging defaultImports, so make sure to include all needed imports
|
|
322
|
+
* in the allowedGlobals array if you use this feature.
|
|
323
|
+
*/
|
|
139
324
|
prepareContext(userContext = {}, imports = {}) {
|
|
140
325
|
let context = (0, utils_1.createSafeContext)(userContext, {
|
|
141
326
|
allowBrowserAPIs: this.config.allowBrowserAPIs,
|
|
@@ -155,5 +340,9 @@ class DynaJs {
|
|
|
155
340
|
return context;
|
|
156
341
|
}
|
|
157
342
|
}
|
|
343
|
+
/**
|
|
344
|
+
* Singleton instance of DynaJs
|
|
345
|
+
* @private
|
|
346
|
+
*/
|
|
158
347
|
DynaJs.instance = null;
|
|
159
348
|
exports.default = DynaJs;
|
package/dist/types.d.ts
CHANGED
|
@@ -9,12 +9,6 @@ export interface ExecutionOptions {
|
|
|
9
9
|
timeout?: number;
|
|
10
10
|
strict?: boolean;
|
|
11
11
|
imports?: ModuleImports;
|
|
12
|
-
injectedKeys?: string[];
|
|
13
|
-
useProxy?: boolean;
|
|
14
|
-
}
|
|
15
|
-
export interface ExecutionResult<T = any> {
|
|
16
|
-
result: T;
|
|
17
|
-
executionTime: number;
|
|
18
12
|
}
|
|
19
13
|
export interface DynaJsConfig {
|
|
20
14
|
defaultTimeout?: number;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,aAAa,CAAC;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ticatec/dyna-js",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "A TypeScript library for dynamic code execution using new Function() that works in both Node.js and browser environments",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|