@ticatec/dyna-js 0.0.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ticatec
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,389 @@
1
+ # @ticatec/dyna-js
2
+
3
+ [![npm version](https://badge.fury.io/js/@ticatec%2Fdyna-js.svg)](https://badge.fury.io/js/@ticatec%2Fdyna-js)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)
6
+ [![Node.js](https://img.shields.io/badge/Node.js-14%2B-green.svg)](https://nodejs.org/)
7
+
8
+ [中文文档](README_CN.md)
9
+
10
+ A TypeScript library for safe dynamic code execution using `new Function()` that works in both Node.js and browser environments.
11
+
12
+ ## Features
13
+
14
+ ✅ **Universal Compatibility** - Works in both Node.js and browser environments
15
+ ✅ **TypeScript Support** - Full type safety with comprehensive type definitions
16
+ ✅ **Singleton Pattern** - Initialize once, use anywhere
17
+ ✅ **Module Imports** - Pre-define classes and functions for dynamic code
18
+ ✅ **Proxy-based Sandbox** - Safe variable access control with proxy mechanism
19
+ ✅ **Configurable Security** - Fine-grained control over allowed APIs and operations
20
+ ✅ **Form Class Creation** - Special method for creating dynamic form classes
21
+ ✅ **Multiple Build Formats** - CommonJS and ESM support
22
+ ✅ **Performance Monitoring** - Built-in execution time tracking
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ npm install @ticatec/dyna-js
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ ### 1. Initialize Once (Application Startup)
33
+
34
+ ```typescript
35
+ import { initializeDynaJs } from '@ticatec/dyna-js';
36
+
37
+ // Initialize with your classes and functions
38
+ initializeDynaJs({
39
+ defaultImports: {
40
+ FlexiForm: FlexiFormClass,
41
+ FlexiCard: FlexiCardClass,
42
+ Dialog: DialogClass,
43
+ MessageBox: MessageBoxClass,
44
+ FlexiContext: FlexiContextClass,
45
+ ModuleLoader: ModuleLoaderClass
46
+ },
47
+ defaultInjectedKeys: ['Dialog', 'MessageBox', 'Indicator', 'Toast'],
48
+ useProxyByDefault: true,
49
+ allowBrowserAPIs: false, // Secure by default
50
+ validateCode: true
51
+ });
52
+ ```
53
+
54
+ ### 2. Use Anywhere
55
+
56
+ ```typescript
57
+ import { getDynaJs } from '@ticatec/dyna-js';
58
+
59
+ // Get the initialized loader
60
+ const loader = getDynaJs();
61
+
62
+ // Create form classes
63
+ const MyFormClass = loader.createFormClass(`
64
+ class CustomForm extends FlexiForm {
65
+ constructor() {
66
+ super();
67
+ this.dialog = Dialog; // Auto-injected
68
+ }
69
+
70
+ show() {
71
+ MessageBox.info('Form is ready!'); // Auto-injected
72
+ }
73
+
74
+ render() {
75
+ return new FlexiCard({
76
+ title: 'Dynamic Form',
77
+ content: 'Created dynamically!'
78
+ });
79
+ }
80
+ }
81
+ return CustomForm;
82
+ `);
83
+
84
+ // Instantiate and use
85
+ const form = new MyFormClass();
86
+ form.show();
87
+ ```
88
+
89
+ ## API Reference
90
+
91
+ ### Core Methods
92
+
93
+ #### `createFormClass<T>(code: string, context?: object, injectedKeys?: string[]): T`
94
+
95
+ Creates a form class with proxy-based sandbox execution.
96
+
97
+ ```typescript
98
+ const FormClass = loader.createFormClass(`
99
+ class MyForm extends FlexiForm {
100
+ constructor() {
101
+ super();
102
+ this.setupDialog();
103
+ }
104
+
105
+ setupDialog() {
106
+ this.dialog = new Dialog({
107
+ title: 'Dynamic Dialog'
108
+ });
109
+ }
110
+ }
111
+ return MyForm;
112
+ `, {
113
+ customData: 'additional context'
114
+ }, ['extraKey']);
115
+ ```
116
+
117
+ #### `executeSync<T>(code: string, options?: ExecutionOptions): ExecutionResult<T>`
118
+
119
+ Synchronously execute code with result and timing information.
120
+
121
+ ```typescript
122
+ const result = loader.executeSync(`
123
+ const form = new FlexiForm();
124
+ form.setTitle('Dynamic Form');
125
+ return form;
126
+ `);
127
+
128
+ console.log(result.result); // FlexiForm instance
129
+ console.log(result.executionTime); // Execution time in milliseconds
130
+ ```
131
+
132
+ #### `execute<T>(code: string, options?: ExecutionOptions): Promise<ExecutionResult<T>>`
133
+
134
+ Asynchronously execute code with timeout support.
135
+
136
+ ```typescript
137
+ const result = await loader.execute(`
138
+ return new Promise(resolve => {
139
+ const form = new FlexiForm();
140
+ resolve(form);
141
+ });
142
+ `, {
143
+ timeout: 3000,
144
+ context: { customVar: 'value' }
145
+ });
146
+ ```
147
+
148
+ #### `executeWithImports<T>(code: string, imports: object, options?: ExecutionOptions): ExecutionResult<T>`
149
+
150
+ Execute code with additional temporary imports.
151
+
152
+ ```typescript
153
+ const result = loader.executeWithImports(`
154
+ return new CustomComponent({
155
+ message: 'Hello from dynamic code!'
156
+ });
157
+ `, {
158
+ CustomComponent: MyCustomComponent,
159
+ utils: myUtilsLibrary
160
+ });
161
+ ```
162
+
163
+ ### Configuration Options
164
+
165
+ ```typescript
166
+ interface DynaJsConfig {
167
+ defaultTimeout?: number; // Default: 5000ms
168
+ defaultStrict?: boolean; // Default: true
169
+ allowedGlobals?: string[]; // Whitelist of allowed global variables
170
+ blockedGlobals?: string[]; // Blacklist of blocked variables
171
+ defaultImports?: object; // Pre-imported classes/functions
172
+ defaultInjectedKeys?: string[]; // Auto-injected variable names
173
+ useProxyByDefault?: boolean; // Default: true
174
+ allowTimers?: boolean; // Allow setTimeout/setInterval (Default: false)
175
+ allowDynamicImports?: boolean; // Allow import()/require() (Default: false)
176
+ validateCode?: boolean; // Enable code validation (Default: true)
177
+ allowBrowserAPIs?: boolean; // Allow window/document access (Default: false)
178
+ allowNodeAPIs?: boolean; // Allow process/require access (Default: false)
179
+ }
180
+ ```
181
+
182
+ ## Security Configurations
183
+
184
+ ### 🔒 **Strict Mode (Recommended, Default)**
185
+
186
+ ```typescript
187
+ initializeDynaJs({
188
+ defaultImports: { FlexiForm, Dialog },
189
+ allowBrowserAPIs: false, // Block window, document, localStorage
190
+ allowNodeAPIs: false, // Block process, require
191
+ allowTimers: false, // Block setTimeout/setInterval
192
+ validateCode: true // Enable code pattern validation
193
+ });
194
+
195
+ // ❌ These will be blocked:
196
+ // window.location.href = 'malicious-site.com'
197
+ // localStorage.clear()
198
+ // setTimeout(maliciousFunction, 1000)
199
+ ```
200
+
201
+ ### 🟡 **Permissive Mode**
202
+
203
+ ```typescript
204
+ initializeDynaJs({
205
+ defaultImports: { FlexiForm, Dialog },
206
+ allowBrowserAPIs: true, // ✅ Allow browser APIs
207
+ allowTimers: true, // ✅ Allow timers
208
+ allowDynamicImports: true, // ✅ Allow dynamic imports
209
+ validateCode: false // Disable validation
210
+ });
211
+
212
+ // ✅ Now allowed:
213
+ // document.getElementById('myDiv')
214
+ // localStorage.getItem('data')
215
+ // setTimeout(() => {}, 1000)
216
+ ```
217
+
218
+ ### 🎯 **Balanced Mode (Recommended for Form Creation)**
219
+
220
+ ```typescript
221
+ initializeDynaJs({
222
+ defaultImports: {
223
+ FlexiForm, Dialog, MessageBox,
224
+ // Provide safe DOM access
225
+ safeDOM: {
226
+ getElementById: (id) => document.getElementById(id),
227
+ createElement: (tag) => document.createElement(tag)
228
+ }
229
+ },
230
+ allowBrowserAPIs: false, // Still secure
231
+ allowTimers: false, // No timers needed for forms
232
+ validateCode: true, // Keep validation
233
+ defaultInjectedKeys: ['window'] // Only inject window reference
234
+ });
235
+ ```
236
+
237
+ ## Advanced Examples
238
+
239
+ ### Creating Dynamic Form Components
240
+
241
+ ```typescript
242
+ const DynamicFormBuilder = loader.createFormClass(`
243
+ class FormBuilder extends FlexiForm {
244
+ constructor(config) {
245
+ super();
246
+ this.config = config;
247
+ this.components = [];
248
+ }
249
+
250
+ addField(fieldConfig) {
251
+ const field = new FlexiCard({
252
+ title: fieldConfig.label,
253
+ content: this.createInput(fieldConfig.type)
254
+ });
255
+ this.components.push(field);
256
+ return this;
257
+ }
258
+
259
+ createInput(type) {
260
+ switch(type) {
261
+ case 'text':
262
+ return '<input type="text" />';
263
+ case 'number':
264
+ return '<input type="number" />';
265
+ default:
266
+ return '<input type="text" />';
267
+ }
268
+ }
269
+
270
+ build() {
271
+ return this.components;
272
+ }
273
+
274
+ show() {
275
+ const dialog = new Dialog({
276
+ title: this.config.title,
277
+ content: this.render()
278
+ });
279
+ dialog.show();
280
+ }
281
+
282
+ render() {
283
+ return this.components.map(c => c.render()).join('');
284
+ }
285
+ }
286
+
287
+ return FormBuilder;
288
+ `);
289
+
290
+ // Use the dynamically created form builder
291
+ const formBuilder = new DynamicFormBuilder({
292
+ title: 'Dynamic Contact Form'
293
+ });
294
+
295
+ formBuilder
296
+ .addField({ label: 'Name', type: 'text' })
297
+ .addField({ label: 'Age', type: 'number' })
298
+ .show();
299
+ ```
300
+
301
+ ### Function Creation
302
+
303
+ ```typescript
304
+ const dynamicValidator = loader.createFunction(`
305
+ return function validateForm(formData) {
306
+ const errors = [];
307
+
308
+ if (!formData.name) {
309
+ errors.push('Name is required');
310
+ }
311
+
312
+ if (!formData.email || !formData.email.includes('@')) {
313
+ errors.push('Valid email is required');
314
+ }
315
+
316
+ return {
317
+ isValid: errors.length === 0,
318
+ errors: errors
319
+ };
320
+ };
321
+ `, []);
322
+
323
+ // Use the dynamic function
324
+ const validation = dynamicValidator({
325
+ name: 'John',
326
+ email: 'john@example.com'
327
+ });
328
+ ```
329
+
330
+ ## Error Handling
331
+
332
+ ```typescript
333
+ try {
334
+ const result = loader.executeSync(`
335
+ // Some dynamic code that might fail
336
+ return new NonExistentClass();
337
+ `);
338
+ } catch (error) {
339
+ console.error('Execution failed:', error.message);
340
+ // Error includes execution time and detailed error information
341
+ }
342
+ ```
343
+
344
+ ## Browser Support
345
+
346
+ - Chrome 51+
347
+ - Firefox 40+
348
+ - Safari 10+
349
+ - Edge 14+
350
+ - Node.js 14+
351
+
352
+ ## TypeScript Support
353
+
354
+ Full TypeScript support with comprehensive type definitions:
355
+
356
+ ```typescript
357
+ import {
358
+ DynaJs,
359
+ ExecutionResult,
360
+ ExecutionOptions,
361
+ ModuleImports
362
+ } from '@ticatec/dyna-js';
363
+ ```
364
+
365
+ ## Contributing
366
+
367
+ 1. Fork the repository
368
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
369
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
370
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
371
+ 5. Open a Pull Request
372
+
373
+ ## License
374
+
375
+ MIT License - see the [LICENSE](LICENSE) file for details.
376
+
377
+ ## Security Considerations
378
+
379
+ ⚠️ **Important Security Notes:**
380
+
381
+ 1. **Code Validation**: Always keep `validateCode: true` in production
382
+ 2. **API Restrictions**: Be careful when enabling `allowBrowserAPIs` or `allowNodeAPIs`
383
+ 3. **Input Sanitization**: Validate all dynamic code input from external sources
384
+ 4. **Timeout Settings**: Set appropriate timeouts to prevent infinite loops
385
+ 5. **Principle of Least Privilege**: Only import the minimum required functions and classes
386
+
387
+ ## Support
388
+
389
+ For issues and feature requests, please use the [GitHub Issues](https://github.com/ticatec-auckland/common-web-library/issues) page.