@zucker-framework/script 1.0.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/dist/index.mjs ADDED
@@ -0,0 +1,549 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
+ }) : x)(function(x) {
6
+ if (typeof require !== "undefined") return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
9
+
10
+ // src/script-factory.ts
11
+ import { Injectable, Logger } from "@nestjs/common";
12
+
13
+ // src/sandbox.ts
14
+ import vm from "vm";
15
+ var BLOCKED_GLOBALS = [
16
+ "process",
17
+ "require",
18
+ "module",
19
+ "exports",
20
+ "__filename",
21
+ "__dirname",
22
+ "globalThis",
23
+ "global",
24
+ "root",
25
+ "GLOBAL",
26
+ "setTimeout",
27
+ "setInterval",
28
+ "setImmediate",
29
+ "clearTimeout",
30
+ "clearInterval",
31
+ "clearImmediate",
32
+ "queueMicrotask"
33
+ ];
34
+ function createSandbox(options) {
35
+ return {
36
+ execute(code, context = {}) {
37
+ const sandbox = {
38
+ ...context,
39
+ console: {
40
+ log: /* @__PURE__ */ __name((...args) => console.log("[sandbox]", ...args), "log"),
41
+ warn: /* @__PURE__ */ __name((...args) => console.warn("[sandbox]", ...args), "warn"),
42
+ error: /* @__PURE__ */ __name((...args) => console.error("[sandbox]", ...args), "error")
43
+ },
44
+ require: createRestrictedRequire(options.allowedModules)
45
+ };
46
+ for (const key of BLOCKED_GLOBALS) {
47
+ sandbox[key] = void 0;
48
+ }
49
+ const vmContext = vm.createContext(sandbox);
50
+ vm.runInContext(`(function() {
51
+ var ObjProto = Object.getPrototypeOf({});
52
+ var FuncProto = Object.getPrototypeOf(function(){});
53
+ Object.defineProperty(ObjProto, 'constructor', { value: undefined, writable: false, configurable: false });
54
+ Object.defineProperty(FuncProto, 'constructor', { value: undefined, writable: false, configurable: false });
55
+ })()`, vmContext, {
56
+ timeout: 1e3
57
+ });
58
+ const wrappedCode = `(function(__args) { ${code} })(typeof __args !== 'undefined' ? __args : [])`;
59
+ return vm.runInContext(wrappedCode, vmContext, {
60
+ timeout: options.timeout,
61
+ filename: "sandbox-script.js"
62
+ });
63
+ }
64
+ };
65
+ }
66
+ __name(createSandbox, "createSandbox");
67
+ function createRestrictedRequire(allowedModules) {
68
+ if (allowedModules.length === 0) return void 0;
69
+ return (moduleName) => {
70
+ if (!allowedModules.includes(moduleName)) {
71
+ throw new Error(`Module not allowed in sandbox: ${moduleName}`);
72
+ }
73
+ return __require(moduleName);
74
+ };
75
+ }
76
+ __name(createRestrictedRequire, "createRestrictedRequire");
77
+
78
+ // src/interface-binding.ts
79
+ function bindInterface(script, interfaceKeys) {
80
+ let cachedExports = null;
81
+ const getExports = /* @__PURE__ */ __name(async () => {
82
+ if (!cachedExports) {
83
+ const result = await script.call();
84
+ if (typeof result !== "object" || result === null) {
85
+ throw new Error("Script must return an object with methods");
86
+ }
87
+ cachedExports = result;
88
+ }
89
+ return cachedExports;
90
+ }, "getExports");
91
+ return new Proxy({}, {
92
+ get(_target, prop) {
93
+ if (!interfaceKeys.includes(prop)) {
94
+ return void 0;
95
+ }
96
+ return async (...args) => {
97
+ const exports = await getExports();
98
+ const fn = exports[prop];
99
+ if (typeof fn !== "function") {
100
+ throw new Error(`Script does not export method: ${prop}`);
101
+ }
102
+ return fn(...args);
103
+ };
104
+ }
105
+ });
106
+ }
107
+ __name(bindInterface, "bindInterface");
108
+
109
+ // src/script-factory.ts
110
+ function _ts_decorate(decorators, target, key, desc) {
111
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
112
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
113
+ r = Reflect.decorate(decorators, target, key, desc);
114
+ } else {
115
+ for (var i = decorators.length - 1; i >= 0; i--) {
116
+ if (d = decorators[i]) {
117
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
118
+ }
119
+ }
120
+ }
121
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
122
+ }
123
+ __name(_ts_decorate, "_ts_decorate");
124
+ var JavaScriptScriptFactory = class _JavaScriptScriptFactory {
125
+ static {
126
+ __name(this, "JavaScriptScriptFactory");
127
+ }
128
+ logger = new Logger(_JavaScriptScriptFactory.name);
129
+ defaultOptions = {
130
+ timeout: 5e3,
131
+ allowedModules: []
132
+ };
133
+ accessControl = {
134
+ allowedModules: /* @__PURE__ */ new Set(),
135
+ deniedPatterns: /* @__PURE__ */ new Set([
136
+ "*"
137
+ ]),
138
+ allowedPatterns: /* @__PURE__ */ new Set()
139
+ };
140
+ setDefaultOptions(options) {
141
+ this.defaultOptions = {
142
+ ...this.defaultOptions,
143
+ ...options
144
+ };
145
+ }
146
+ /** 添加允许的模块 — 对齐 jetlinks allows() */
147
+ allowModule(moduleName) {
148
+ this.accessControl.allowedModules.add(moduleName);
149
+ }
150
+ /** 移除允许的模块 — 对齐 jetlinks denies() */
151
+ denyModule(moduleName) {
152
+ this.accessControl.allowedModules.delete(moduleName);
153
+ }
154
+ /** 添加允许的模式(正则) — 对齐 jetlinks allowsPattern() */
155
+ allowPattern(pattern) {
156
+ this.accessControl.allowedPatterns.add(pattern);
157
+ }
158
+ /** 添加拒绝的模式(正则) — 对齐 jetlinks deniesPattern() */
159
+ denyPattern(pattern) {
160
+ this.accessControl.deniedPatterns.add(pattern);
161
+ }
162
+ /** 检查模块是否被拒绝 — 对齐 jetlinks isDenied() */
163
+ isDenied(moduleName) {
164
+ if (this.accessControl.allowedModules.has(moduleName)) {
165
+ return false;
166
+ }
167
+ for (const pattern of this.accessControl.allowedPatterns) {
168
+ if (new RegExp(pattern).test(moduleName)) {
169
+ return false;
170
+ }
171
+ }
172
+ if (this.accessControl.deniedPatterns.has("*")) {
173
+ return true;
174
+ }
175
+ for (const pattern of this.accessControl.deniedPatterns) {
176
+ if (new RegExp(pattern).test(moduleName)) {
177
+ return true;
178
+ }
179
+ }
180
+ return false;
181
+ }
182
+ /**
183
+ * 将脚本返回值转换为纯 JS 类型 — 对齐 jetlinks AbstractScriptFactory.convertToJavaType()。
184
+ * 确保 Map、Set 等非 JSON 安全类型被转为 POJO/Array。
185
+ */
186
+ convertToJavaType(data) {
187
+ if (data === void 0 || data === null) {
188
+ return data;
189
+ }
190
+ if (data instanceof Map) {
191
+ const obj = {};
192
+ for (const [key, value] of data) {
193
+ obj[String(key)] = this.convertToJavaType(value);
194
+ }
195
+ return obj;
196
+ }
197
+ if (data instanceof Set) {
198
+ return Array.from(data).map((v) => this.convertToJavaType(v));
199
+ }
200
+ if (Array.isArray(data)) {
201
+ return data.map((v) => this.convertToJavaType(v));
202
+ }
203
+ return data;
204
+ }
205
+ async compile(script) {
206
+ return this.compileExpose(script, {});
207
+ }
208
+ async compileExpose(script, expose) {
209
+ this.logger.debug(`Compiling script: ${script.name}`);
210
+ const allowedModules = Array.from(this.accessControl.allowedModules);
211
+ const sandboxOptions = {
212
+ ...this.defaultOptions,
213
+ name: script.name,
214
+ allowedModules: [
215
+ ...this.defaultOptions.allowedModules,
216
+ ...allowedModules
217
+ ]
218
+ };
219
+ return {
220
+ call: /* @__PURE__ */ __name(async (...args) => {
221
+ const sandbox = createSandbox(sandboxOptions);
222
+ return sandbox.execute(script.content, {
223
+ ...expose,
224
+ __args: args
225
+ });
226
+ }, "call"),
227
+ callWithContext: /* @__PURE__ */ __name(async (context, ...args) => {
228
+ const sandbox = createSandbox(sandboxOptions);
229
+ return sandbox.execute(script.content, {
230
+ ...expose,
231
+ ...context,
232
+ __args: args
233
+ });
234
+ }, "callWithContext"),
235
+ callWithExecutionContext: /* @__PURE__ */ __name(async (execCtx) => {
236
+ const sandbox = createSandbox(sandboxOptions);
237
+ return sandbox.execute(script.content, {
238
+ ...expose,
239
+ ...execCtx.toRecord()
240
+ });
241
+ }, "callWithExecutionContext")
242
+ };
243
+ }
244
+ async bind(script, context) {
245
+ return this.compileExpose(script, context);
246
+ }
247
+ async createProxy(script, interfaceKeys) {
248
+ const compiled = await this.compile(script);
249
+ return bindInterface(compiled, interfaceKeys);
250
+ }
251
+ };
252
+ JavaScriptScriptFactory = _ts_decorate([
253
+ Injectable()
254
+ ], JavaScriptScriptFactory);
255
+
256
+ // src/exposed-script.ts
257
+ var ExposedScriptRegistry = class {
258
+ static {
259
+ __name(this, "ExposedScriptRegistry");
260
+ }
261
+ methods = /* @__PURE__ */ new Map();
262
+ register(name, fn) {
263
+ this.methods.set(name, fn);
264
+ }
265
+ unregister(name) {
266
+ this.methods.delete(name);
267
+ }
268
+ getExposedMethods() {
269
+ const result = {};
270
+ for (const [name, fn] of this.methods) {
271
+ result[name] = fn;
272
+ }
273
+ return result;
274
+ }
275
+ has(name) {
276
+ return this.methods.has(name);
277
+ }
278
+ getNames() {
279
+ return Array.from(this.methods.keys());
280
+ }
281
+ };
282
+
283
+ // src/execution-context.ts
284
+ var DefaultExecutionContext = class {
285
+ static {
286
+ __name(this, "DefaultExecutionContext");
287
+ }
288
+ layers;
289
+ selfLayer;
290
+ constructor(...contexts) {
291
+ this.layers = contexts.map((c) => c);
292
+ this.selfLayer = /* @__PURE__ */ new Map();
293
+ }
294
+ getAttribute(name) {
295
+ for (const layer of this.layers) {
296
+ if (layer instanceof Map) {
297
+ if (layer.has(name)) return layer.get(name);
298
+ } else {
299
+ if (name in layer) return layer[name];
300
+ }
301
+ }
302
+ if (this.selfLayer.has(name)) return this.selfLayer.get(name);
303
+ return void 0;
304
+ }
305
+ setAttribute(name, value) {
306
+ this.selfLayer.set(name, value);
307
+ }
308
+ removeAttribute(name) {
309
+ const existing = this.selfLayer.get(name);
310
+ this.selfLayer.delete(name);
311
+ return existing;
312
+ }
313
+ hasAttribute(name) {
314
+ for (const layer of this.layers) {
315
+ if (layer instanceof Map) {
316
+ if (layer.has(name)) return true;
317
+ } else {
318
+ if (name in layer) return true;
319
+ }
320
+ }
321
+ return this.selfLayer.has(name);
322
+ }
323
+ merge(other) {
324
+ return new CompositeExecutionContext(this, other);
325
+ }
326
+ toRecord() {
327
+ const result = {};
328
+ for (const entry of this.selfLayer.entries()) {
329
+ result[entry[0]] = entry[1];
330
+ }
331
+ for (let i = this.layers.length - 1; i >= 0; i--) {
332
+ const layer = this.layers[i];
333
+ if (layer instanceof Map) {
334
+ for (const entry of layer.entries()) {
335
+ result[entry[0]] = entry[1];
336
+ }
337
+ } else {
338
+ Object.assign(result, layer);
339
+ }
340
+ }
341
+ return result;
342
+ }
343
+ };
344
+ var CompositeExecutionContext = class {
345
+ static {
346
+ __name(this, "CompositeExecutionContext");
347
+ }
348
+ contexts;
349
+ constructor(...contexts) {
350
+ this.contexts = [
351
+ ...contexts
352
+ ];
353
+ }
354
+ getAttribute(name) {
355
+ for (const ctx of this.contexts) {
356
+ if (ctx.hasAttribute(name)) {
357
+ return ctx.getAttribute(name);
358
+ }
359
+ }
360
+ return void 0;
361
+ }
362
+ setAttribute(name, value) {
363
+ if (this.contexts.length > 0) {
364
+ this.contexts[this.contexts.length - 1].setAttribute(name, value);
365
+ }
366
+ }
367
+ removeAttribute(name) {
368
+ for (const ctx of this.contexts) {
369
+ if (ctx.hasAttribute(name)) {
370
+ return ctx.removeAttribute(name);
371
+ }
372
+ }
373
+ return void 0;
374
+ }
375
+ hasAttribute(name) {
376
+ return this.contexts.some((ctx) => ctx.hasAttribute(name));
377
+ }
378
+ merge(other) {
379
+ this.contexts = [
380
+ ...this.contexts,
381
+ other
382
+ ];
383
+ return this;
384
+ }
385
+ toRecord() {
386
+ const result = {};
387
+ for (let i = this.contexts.length - 1; i >= 0; i--) {
388
+ Object.assign(result, this.contexts[i].toRecord());
389
+ }
390
+ return result;
391
+ }
392
+ };
393
+ function createExecutionContext(...contexts) {
394
+ return new DefaultExecutionContext(...contexts);
395
+ }
396
+ __name(createExecutionContext, "createExecutionContext");
397
+ function composeContexts(...contexts) {
398
+ return new CompositeExecutionContext(...contexts);
399
+ }
400
+ __name(composeContexts, "composeContexts");
401
+
402
+ // src/script-utils.ts
403
+ import { createHash } from "crypto";
404
+ var ScriptUtils = class {
405
+ static {
406
+ __name(this, "ScriptUtils");
407
+ }
408
+ /** 当前时间戳(毫秒) */
409
+ now() {
410
+ return Date.now();
411
+ }
412
+ /** 格式化当前时间 */
413
+ nowFormatted(format) {
414
+ const d = /* @__PURE__ */ new Date();
415
+ if (!format) return d.toISOString();
416
+ return format.replace("yyyy", String(d.getFullYear())).replace("MM", String(d.getMonth() + 1).padStart(2, "0")).replace("dd", String(d.getDate()).padStart(2, "0")).replace("HH", String(d.getHours()).padStart(2, "0")).replace("mm", String(d.getMinutes()).padStart(2, "0")).replace("ss", String(d.getSeconds()).padStart(2, "0"));
417
+ }
418
+ /** 创建新的 Map(对象) */
419
+ newMap() {
420
+ return {};
421
+ }
422
+ /** 创建新的数组 */
423
+ newList() {
424
+ return [];
425
+ }
426
+ /** 序列化为 JSON 字符串 */
427
+ toJsonString(obj) {
428
+ return JSON.stringify(obj);
429
+ }
430
+ /** 解析 JSON 字符串 */
431
+ parseJson(json) {
432
+ return JSON.parse(json);
433
+ }
434
+ /** 转换为 Java/原生类型(identity in JS) */
435
+ toJavaType(obj) {
436
+ return obj;
437
+ }
438
+ /** 求最大值(支持数组、嵌套集合) */
439
+ max(...params) {
440
+ let maxVal = void 0;
441
+ for (let param of params) {
442
+ if (param && typeof param === "object" && !Array.isArray(param)) {
443
+ param = Object.values(param);
444
+ }
445
+ if (Array.isArray(param)) {
446
+ param = this.max(...param);
447
+ }
448
+ if (maxVal === void 0) {
449
+ maxVal = param;
450
+ continue;
451
+ }
452
+ if (Number(param) > Number(maxVal)) {
453
+ maxVal = param;
454
+ }
455
+ }
456
+ return maxVal;
457
+ }
458
+ /** 求最小值(支持数组、嵌套集合) */
459
+ min(...params) {
460
+ let minVal = void 0;
461
+ for (let param of params) {
462
+ if (param && typeof param === "object" && !Array.isArray(param)) {
463
+ param = Object.values(param);
464
+ }
465
+ if (Array.isArray(param)) {
466
+ param = this.min(...param);
467
+ }
468
+ if (minVal === void 0) {
469
+ minVal = param;
470
+ continue;
471
+ }
472
+ if (Number(param) < Number(minVal)) {
473
+ minVal = param;
474
+ }
475
+ }
476
+ return minVal;
477
+ }
478
+ /** SHA1 摘要(hex) */
479
+ sha1Hex(str) {
480
+ if (str == null) return null;
481
+ return createHash("sha1").update(str).digest("hex");
482
+ }
483
+ /** MD5 摘要(hex) */
484
+ md5Hex(str) {
485
+ if (str == null) return null;
486
+ return createHash("md5").update(str).digest("hex");
487
+ }
488
+ /** 创建指定大小的 Buffer */
489
+ newByteArray(size) {
490
+ return Buffer.alloc(size);
491
+ }
492
+ /** 创建指定大小的 Int32 数组 — 对齐 jetlinks Utils.newIntArray() */
493
+ newIntArray(size) {
494
+ return new Int32Array(size);
495
+ }
496
+ /** 创建指定大小的 BigInt64 数组 — 对齐 jetlinks Utils.newLongArray() */
497
+ newLongArray(size) {
498
+ return new BigInt64Array(size);
499
+ }
500
+ };
501
+ var scriptUtils = new ScriptUtils();
502
+
503
+ // src/script.module.ts
504
+ import { Module, Global } from "@nestjs/common";
505
+ function _ts_decorate2(decorators, target, key, desc) {
506
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
507
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
508
+ r = Reflect.decorate(decorators, target, key, desc);
509
+ } else {
510
+ for (var i = decorators.length - 1; i >= 0; i--) {
511
+ if (d = decorators[i]) {
512
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
513
+ }
514
+ }
515
+ }
516
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
517
+ }
518
+ __name(_ts_decorate2, "_ts_decorate");
519
+ var ZuckerScriptModule = class {
520
+ static {
521
+ __name(this, "ZuckerScriptModule");
522
+ }
523
+ };
524
+ ZuckerScriptModule = _ts_decorate2([
525
+ Global(),
526
+ Module({
527
+ providers: [
528
+ JavaScriptScriptFactory,
529
+ ExposedScriptRegistry
530
+ ],
531
+ exports: [
532
+ JavaScriptScriptFactory,
533
+ ExposedScriptRegistry
534
+ ]
535
+ })
536
+ ], ZuckerScriptModule);
537
+ export {
538
+ CompositeExecutionContext,
539
+ DefaultExecutionContext,
540
+ ExposedScriptRegistry,
541
+ JavaScriptScriptFactory,
542
+ ScriptUtils,
543
+ ZuckerScriptModule,
544
+ bindInterface,
545
+ composeContexts,
546
+ createExecutionContext,
547
+ createSandbox,
548
+ scriptUtils
549
+ };
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@zucker-framework/script",
3
+ "version": "1.0.0",
4
+ "main": "dist/index.js",
5
+ "module": "dist/index.mjs",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "LICENSE",
10
+ "NOTICE",
11
+ "THIRD_PARTY_NOTICES"
12
+ ],
13
+ "dependencies": {
14
+ "@zucker-framework/core": "1.0.0"
15
+ },
16
+ "peerDependencies": {
17
+ "@nestjs/common": "^12.0.0",
18
+ "@nestjs/core": "^12.0.0"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "^20.19.43"
22
+ },
23
+ "license": "Apache-2.0",
24
+ "author": "Lind",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/Lind-pro/zucker-framework.git",
28
+ "directory": "packages/script"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public",
32
+ "registry": "https://registry.npmjs.org/"
33
+ },
34
+ "scripts": {
35
+ "build": "tsup src/index.ts --format cjs,esm --dts",
36
+ "clean": "rm -rf dist",
37
+ "lint": "eslint src/"
38
+ }
39
+ }