@ticatec/dyna-js 0.0.3 → 0.1.0
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 +221 -20
- package/README_CN.md +231 -30
- 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/ModuleLoader.d.ts +93 -0
- package/dist/ModuleLoader.d.ts.map +1 -0
- package/dist/ModuleLoader.esm.js +106 -0
- package/dist/ModuleLoader.js +110 -0
- package/dist/types.d.ts +0 -6
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -3
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;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Function type for checking if a module needs to be updated
|
|
3
|
+
* @param data - Module data containing code and digest information
|
|
4
|
+
* @returns true if the module is up-to-date, false if it needs to be reloaded
|
|
5
|
+
*/
|
|
6
|
+
export type ModuleCheck = (data: any) => boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Function type for loading a module from remote source
|
|
9
|
+
* @param data - Module data containing information needed to load the module
|
|
10
|
+
* @returns Promise that resolves to the loaded module data
|
|
11
|
+
*/
|
|
12
|
+
export type LoadModule = (data: any) => Promise<any>;
|
|
13
|
+
/**
|
|
14
|
+
* Function type for saving a module to local storage
|
|
15
|
+
* @param data - Module data to be saved
|
|
16
|
+
*/
|
|
17
|
+
export type SaveModuleToLocalStorage = (data: any) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Function type for loading a module from local storage
|
|
20
|
+
* @param data - Module identifier or data
|
|
21
|
+
* @returns The module script text
|
|
22
|
+
*/
|
|
23
|
+
export type LoadLocalModule = (data: any) => string;
|
|
24
|
+
/**
|
|
25
|
+
* Configuration options for ModuleLoader
|
|
26
|
+
*/
|
|
27
|
+
export interface ModuleLoaderOptions {
|
|
28
|
+
/** Optional custom module check function */
|
|
29
|
+
moduleCheck?: ModuleCheck;
|
|
30
|
+
/** Optional custom save module function */
|
|
31
|
+
saveModule?: SaveModuleToLocalStorage;
|
|
32
|
+
/** Optional custom load local module function */
|
|
33
|
+
loadLocalModule?: LoadLocalModule;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* ModuleLoader is a singleton class for managing dynamic module loading with caching
|
|
37
|
+
* It supports checking for module updates, loading from remote sources, and caching in localStorage
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const loader = ModuleLoader.initialize(
|
|
42
|
+
* async (data) => fetch(`/api/modules/${data.code}`).then(r => r.json()),
|
|
43
|
+
* {}
|
|
44
|
+
* );
|
|
45
|
+
*
|
|
46
|
+
* await loader.checkFreshScripts([{ code: 'module1', digest: 'abc123' }]);
|
|
47
|
+
* const module = loader.createModule('module1', { React, ReactDOM });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export default class ModuleLoader {
|
|
51
|
+
private static instance;
|
|
52
|
+
private readonly loadModule;
|
|
53
|
+
private readonly moduleCheck;
|
|
54
|
+
private readonly saveModule;
|
|
55
|
+
private readonly loadLocalModule;
|
|
56
|
+
private modulesMap;
|
|
57
|
+
/**
|
|
58
|
+
* Private constructor for singleton pattern
|
|
59
|
+
* @param loadModule - Function to load module from remote
|
|
60
|
+
* @param moduleCheck - Function to check module freshness
|
|
61
|
+
* @param saveModule - Function to save module locally
|
|
62
|
+
* @param loadLocalModule - Function to load module from local storage
|
|
63
|
+
*/
|
|
64
|
+
private constructor();
|
|
65
|
+
/**
|
|
66
|
+
* Initialize the ModuleLoader singleton instance
|
|
67
|
+
* @param loadModule - Function to load module from remote source
|
|
68
|
+
* @param options - Configuration options with optional custom implementations
|
|
69
|
+
* @returns The singleton ModuleLoader instance
|
|
70
|
+
*/
|
|
71
|
+
static initialize(loadModule: LoadModule, options: ModuleLoaderOptions): ModuleLoader;
|
|
72
|
+
/**
|
|
73
|
+
* Check and update modules that are not fresh
|
|
74
|
+
* Iterates through the list, checks each module, and reloads if needed
|
|
75
|
+
* Clears the module cache after checking all modules
|
|
76
|
+
*
|
|
77
|
+
* @param list - Array of module data objects to check
|
|
78
|
+
* @returns Promise that resolves when all modules are checked and updated
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
checkFreshScripts(list: Array<any>): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Create or retrieve a cached module instance
|
|
84
|
+
* Loads the module script from local storage and executes it with provided imports
|
|
85
|
+
* Caches the result for subsequent calls
|
|
86
|
+
*
|
|
87
|
+
* @param key - The module key/code to load
|
|
88
|
+
* @param imports - Object containing dependencies to inject into the module
|
|
89
|
+
* @returns The instantiated module
|
|
90
|
+
*/
|
|
91
|
+
createModule(key: string, imports: any): any;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=ModuleLoader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModuleLoader.d.ts","sourceRoot":"","sources":["../src/ModuleLoader.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC;AAEjD;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;AAErD;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;AAE3D;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,GAAG,KAAK,MAAM,CAAC;AA+BpD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAChC,4CAA4C;IAC5C,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,2CAA2C;IAC3C,UAAU,CAAC,EAAE,wBAAwB,CAAC;IACtC,iDAAiD;IACjD,eAAe,CAAC,EAAE,eAAe,CAAA;CACpC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,OAAO,OAAO,YAAY;IAE7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IACxC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA2B;IACtD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAClD,OAAO,CAAC,UAAU,CAAmB;IAErC;;;;;;OAMG;IACH,OAAO;IAQP;;;;;OAKG;IACH,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,mBAAmB,GAAG,YAAY;IAQrF;;;;;;;;OAQG;IACG,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC;IAUxC;;;;;;;;OAQG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,GAAG;CAU/C"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { getDynaJs } from "./index";
|
|
2
|
+
/**
|
|
3
|
+
* Default module check function that compares message digest
|
|
4
|
+
* @param data - Module data containing code and digest
|
|
5
|
+
* @returns true if the local digest matches the remote digest
|
|
6
|
+
*/
|
|
7
|
+
const checkMessageDigest = (data) => {
|
|
8
|
+
let localDigest = window.localStorage.getItem(`md:${data.code}`);
|
|
9
|
+
return localDigest == data.digest;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Default function to save module to localStorage
|
|
13
|
+
* Saves both the module digest and script text
|
|
14
|
+
* @param data - Module data containing code, digest, and scriptText
|
|
15
|
+
*/
|
|
16
|
+
const saveModule = (data) => {
|
|
17
|
+
window.localStorage.setItem(`md:${data.code}`, data.digest);
|
|
18
|
+
window.localStorage.setItem(`script:${data.code}`, data.scriptText);
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Default function to load module script from localStorage
|
|
22
|
+
* @param key - Module key/code
|
|
23
|
+
* @returns The module script text
|
|
24
|
+
*/
|
|
25
|
+
const loadLocalModule = (key) => {
|
|
26
|
+
return window.localStorage.getItem(`script:${key}`);
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* ModuleLoader is a singleton class for managing dynamic module loading with caching
|
|
30
|
+
* It supports checking for module updates, loading from remote sources, and caching in localStorage
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const loader = ModuleLoader.initialize(
|
|
35
|
+
* async (data) => fetch(`/api/modules/${data.code}`).then(r => r.json()),
|
|
36
|
+
* {}
|
|
37
|
+
* );
|
|
38
|
+
*
|
|
39
|
+
* await loader.checkFreshScripts([{ code: 'module1', digest: 'abc123' }]);
|
|
40
|
+
* const module = loader.createModule('module1', { React, ReactDOM });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export default class ModuleLoader {
|
|
44
|
+
/**
|
|
45
|
+
* Private constructor for singleton pattern
|
|
46
|
+
* @param loadModule - Function to load module from remote
|
|
47
|
+
* @param moduleCheck - Function to check module freshness
|
|
48
|
+
* @param saveModule - Function to save module locally
|
|
49
|
+
* @param loadLocalModule - Function to load module from local storage
|
|
50
|
+
*/
|
|
51
|
+
constructor(loadModule, moduleCheck, saveModule, loadLocalModule) {
|
|
52
|
+
this.loadModule = loadModule;
|
|
53
|
+
this.moduleCheck = moduleCheck;
|
|
54
|
+
this.saveModule = saveModule;
|
|
55
|
+
this.loadLocalModule = loadLocalModule;
|
|
56
|
+
this.modulesMap = new Map();
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Initialize the ModuleLoader singleton instance
|
|
60
|
+
* @param loadModule - Function to load module from remote source
|
|
61
|
+
* @param options - Configuration options with optional custom implementations
|
|
62
|
+
* @returns The singleton ModuleLoader instance
|
|
63
|
+
*/
|
|
64
|
+
static initialize(loadModule, options) {
|
|
65
|
+
if (ModuleLoader.instance == null) {
|
|
66
|
+
ModuleLoader.instance = new ModuleLoader(loadModule, options.moduleCheck ?? checkMessageDigest, options.saveModule ?? saveModule, options.loadLocalModule ?? loadLocalModule);
|
|
67
|
+
}
|
|
68
|
+
return ModuleLoader.instance;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Check and update modules that are not fresh
|
|
72
|
+
* Iterates through the list, checks each module, and reloads if needed
|
|
73
|
+
* Clears the module cache after checking all modules
|
|
74
|
+
*
|
|
75
|
+
* @param list - Array of module data objects to check
|
|
76
|
+
* @returns Promise that resolves when all modules are checked and updated
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
async checkFreshScripts(list) {
|
|
80
|
+
for (let item of list) {
|
|
81
|
+
if (!this.moduleCheck(item)) {
|
|
82
|
+
let data = await this.loadModule(item);
|
|
83
|
+
this.saveModule(data);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
this.modulesMap.clear();
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Create or retrieve a cached module instance
|
|
90
|
+
* Loads the module script from local storage and executes it with provided imports
|
|
91
|
+
* Caches the result for subsequent calls
|
|
92
|
+
*
|
|
93
|
+
* @param key - The module key/code to load
|
|
94
|
+
* @param imports - Object containing dependencies to inject into the module
|
|
95
|
+
* @returns The instantiated module
|
|
96
|
+
*/
|
|
97
|
+
createModule(key, imports) {
|
|
98
|
+
let module = this.modulesMap.get(key);
|
|
99
|
+
if (module == null) {
|
|
100
|
+
let scriptText = this.loadLocalModule(key);
|
|
101
|
+
module = getDynaJs().executeSync(scriptText, { imports });
|
|
102
|
+
this.modulesMap.set(key, module);
|
|
103
|
+
}
|
|
104
|
+
return module;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("./index");
|
|
4
|
+
/**
|
|
5
|
+
* Default module check function that compares message digest
|
|
6
|
+
* @param data - Module data containing code and digest
|
|
7
|
+
* @returns true if the local digest matches the remote digest
|
|
8
|
+
*/
|
|
9
|
+
const checkMessageDigest = (data) => {
|
|
10
|
+
let localDigest = window.localStorage.getItem(`md:${data.code}`);
|
|
11
|
+
return localDigest == data.digest;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Default function to save module to localStorage
|
|
15
|
+
* Saves both the module digest and script text
|
|
16
|
+
* @param data - Module data containing code, digest, and scriptText
|
|
17
|
+
*/
|
|
18
|
+
const saveModule = (data) => {
|
|
19
|
+
window.localStorage.setItem(`md:${data.code}`, data.digest);
|
|
20
|
+
window.localStorage.setItem(`script:${data.code}`, data.scriptText);
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Default function to load module script from localStorage
|
|
24
|
+
* @param key - Module key/code
|
|
25
|
+
* @returns The module script text
|
|
26
|
+
*/
|
|
27
|
+
const loadLocalModule = (key) => {
|
|
28
|
+
return window.localStorage.getItem(`script:${key}`);
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* ModuleLoader is a singleton class for managing dynamic module loading with caching
|
|
32
|
+
* It supports checking for module updates, loading from remote sources, and caching in localStorage
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* const loader = ModuleLoader.initialize(
|
|
37
|
+
* async (data) => fetch(`/api/modules/${data.code}`).then(r => r.json()),
|
|
38
|
+
* {}
|
|
39
|
+
* );
|
|
40
|
+
*
|
|
41
|
+
* await loader.checkFreshScripts([{ code: 'module1', digest: 'abc123' }]);
|
|
42
|
+
* const module = loader.createModule('module1', { React, ReactDOM });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
class ModuleLoader {
|
|
46
|
+
/**
|
|
47
|
+
* Private constructor for singleton pattern
|
|
48
|
+
* @param loadModule - Function to load module from remote
|
|
49
|
+
* @param moduleCheck - Function to check module freshness
|
|
50
|
+
* @param saveModule - Function to save module locally
|
|
51
|
+
* @param loadLocalModule - Function to load module from local storage
|
|
52
|
+
*/
|
|
53
|
+
constructor(loadModule, moduleCheck, saveModule, loadLocalModule) {
|
|
54
|
+
this.loadModule = loadModule;
|
|
55
|
+
this.moduleCheck = moduleCheck;
|
|
56
|
+
this.saveModule = saveModule;
|
|
57
|
+
this.loadLocalModule = loadLocalModule;
|
|
58
|
+
this.modulesMap = new Map();
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Initialize the ModuleLoader singleton instance
|
|
62
|
+
* @param loadModule - Function to load module from remote source
|
|
63
|
+
* @param options - Configuration options with optional custom implementations
|
|
64
|
+
* @returns The singleton ModuleLoader instance
|
|
65
|
+
*/
|
|
66
|
+
static initialize(loadModule, options) {
|
|
67
|
+
var _a, _b, _c;
|
|
68
|
+
if (ModuleLoader.instance == null) {
|
|
69
|
+
ModuleLoader.instance = new ModuleLoader(loadModule, (_a = options.moduleCheck) !== null && _a !== void 0 ? _a : checkMessageDigest, (_b = options.saveModule) !== null && _b !== void 0 ? _b : saveModule, (_c = options.loadLocalModule) !== null && _c !== void 0 ? _c : loadLocalModule);
|
|
70
|
+
}
|
|
71
|
+
return ModuleLoader.instance;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check and update modules that are not fresh
|
|
75
|
+
* Iterates through the list, checks each module, and reloads if needed
|
|
76
|
+
* Clears the module cache after checking all modules
|
|
77
|
+
*
|
|
78
|
+
* @param list - Array of module data objects to check
|
|
79
|
+
* @returns Promise that resolves when all modules are checked and updated
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
async checkFreshScripts(list) {
|
|
83
|
+
for (let item of list) {
|
|
84
|
+
if (!this.moduleCheck(item)) {
|
|
85
|
+
let data = await this.loadModule(item);
|
|
86
|
+
this.saveModule(data);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
this.modulesMap.clear();
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create or retrieve a cached module instance
|
|
93
|
+
* Loads the module script from local storage and executes it with provided imports
|
|
94
|
+
* Caches the result for subsequent calls
|
|
95
|
+
*
|
|
96
|
+
* @param key - The module key/code to load
|
|
97
|
+
* @param imports - Object containing dependencies to inject into the module
|
|
98
|
+
* @returns The instantiated module
|
|
99
|
+
*/
|
|
100
|
+
createModule(key, imports) {
|
|
101
|
+
let module = this.modulesMap.get(key);
|
|
102
|
+
if (module == null) {
|
|
103
|
+
let scriptText = this.loadLocalModule(key);
|
|
104
|
+
module = (0, index_1.getDynaJs)().executeSync(scriptText, { imports });
|
|
105
|
+
this.modulesMap.set(key, module);
|
|
106
|
+
}
|
|
107
|
+
return module;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.default = ModuleLoader;
|
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.1.0",
|
|
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",
|
|
@@ -41,8 +41,7 @@
|
|
|
41
41
|
"license": "MIT",
|
|
42
42
|
"repository": {
|
|
43
43
|
"type": "git",
|
|
44
|
-
"url": "git+https://github.com/ticatec/DynaJS.git"
|
|
45
|
-
"directory": "dynamic-script-loader"
|
|
44
|
+
"url": "git+https://github.com/ticatec/DynaJS.git"
|
|
46
45
|
},
|
|
47
46
|
"bugs": {
|
|
48
47
|
"url": "https://github.com/ticatec/DynaJS/issues"
|