@scriptdb/vm 1.1.0 → 1.1.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/dist/index.d.mts +28 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +83 -44
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +115 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +2 -5
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import vm from 'node:vm';
|
|
2
|
+
|
|
3
|
+
interface VMOptions {
|
|
4
|
+
language?: 'ts' | 'js';
|
|
5
|
+
registerModules?: {
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
declare class VM {
|
|
10
|
+
private transpiler;
|
|
11
|
+
private ctx;
|
|
12
|
+
private registerModules;
|
|
13
|
+
private DATABASE_DIR;
|
|
14
|
+
private SCRIPTDB_DIR;
|
|
15
|
+
private pkgScriptDB;
|
|
16
|
+
constructor(options?: VMOptions);
|
|
17
|
+
register(context: {
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
}): void;
|
|
20
|
+
resolvePath(fileList: any[], query: string): any;
|
|
21
|
+
moduleLinker(specifier: any, referencingModule: any): Promise<vm.SyntheticModule>;
|
|
22
|
+
run(code: string, options?: vm.RunningCodeOptions | string): Promise<{
|
|
23
|
+
namespace: Object;
|
|
24
|
+
logs: any[];
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { VM, VM as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import vm from 'node:vm';
|
|
2
|
+
|
|
3
|
+
interface VMOptions {
|
|
4
|
+
language?: 'ts' | 'js';
|
|
5
|
+
registerModules?: {
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
declare class VM {
|
|
10
|
+
private transpiler;
|
|
11
|
+
private ctx;
|
|
12
|
+
private registerModules;
|
|
13
|
+
private DATABASE_DIR;
|
|
14
|
+
private SCRIPTDB_DIR;
|
|
15
|
+
private pkgScriptDB;
|
|
16
|
+
constructor(options?: VMOptions);
|
|
17
|
+
register(context: {
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
}): void;
|
|
20
|
+
resolvePath(fileList: any[], query: string): any;
|
|
21
|
+
moduleLinker(specifier: any, referencingModule: any): Promise<vm.SyntheticModule>;
|
|
22
|
+
run(code: string, options?: vm.RunningCodeOptions | string): Promise<{
|
|
23
|
+
namespace: Object;
|
|
24
|
+
logs: any[];
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { VM, VM as default };
|
package/dist/index.js
CHANGED
|
@@ -1,38 +1,68 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
8
29
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
VM: () => VM,
|
|
34
|
+
default: () => index_default
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
var import_bun = __toESM(require("bun"));
|
|
38
|
+
var import_node_vm = __toESM(require("vm"));
|
|
39
|
+
var import_node_fs = __toESM(require("fs"));
|
|
40
|
+
var import_node_path = __toESM(require("path"));
|
|
41
|
+
var import_node_os = __toESM(require("os"));
|
|
42
|
+
var VM = class {
|
|
16
43
|
constructor(options) {
|
|
17
|
-
|
|
18
|
-
|
|
44
|
+
this.DATABASE_DIR = import_node_path.default.join(import_node_os.default.homedir(), ".scriptdb", "databases");
|
|
45
|
+
this.SCRIPTDB_DIR = import_node_path.default.join(import_node_os.default.homedir(), ".scriptdb");
|
|
46
|
+
this.pkgScriptDB = {};
|
|
47
|
+
if (!import_node_fs.default.existsSync(this.DATABASE_DIR)) {
|
|
48
|
+
import_node_fs.default.mkdirSync(this.DATABASE_DIR, { recursive: true });
|
|
19
49
|
}
|
|
20
|
-
if (!
|
|
21
|
-
|
|
50
|
+
if (!import_node_fs.default.existsSync(this.SCRIPTDB_DIR)) {
|
|
51
|
+
import_node_fs.default.mkdirSync(this.SCRIPTDB_DIR, { recursive: true });
|
|
22
52
|
}
|
|
23
|
-
const pkgPath =
|
|
24
|
-
if (
|
|
25
|
-
this.pkgScriptDB = JSON.parse(
|
|
53
|
+
const pkgPath = import_node_path.default.join(this.SCRIPTDB_DIR, "package.json");
|
|
54
|
+
if (import_node_fs.default.existsSync(pkgPath)) {
|
|
55
|
+
this.pkgScriptDB = JSON.parse(import_node_fs.default.readFileSync(pkgPath, "utf8"));
|
|
26
56
|
}
|
|
27
|
-
this.transpiler = new
|
|
57
|
+
this.transpiler = new import_bun.default.Transpiler({
|
|
28
58
|
loader: options?.language || "ts"
|
|
29
59
|
});
|
|
30
60
|
this.registerModules = options?.registerModules || {};
|
|
31
|
-
this.ctx =
|
|
61
|
+
this.ctx = import_node_vm.default.createContext(this.registerModules);
|
|
32
62
|
}
|
|
33
63
|
register(context) {
|
|
34
64
|
this.registerModules = { ...this.registerModules, ...context };
|
|
35
|
-
this.ctx =
|
|
65
|
+
this.ctx = import_node_vm.default.createContext(this.registerModules);
|
|
36
66
|
}
|
|
37
67
|
resolvePath(fileList, query) {
|
|
38
68
|
const aliases = { "@db": this.DATABASE_DIR };
|
|
@@ -43,25 +73,29 @@ class VM {
|
|
|
43
73
|
break;
|
|
44
74
|
}
|
|
45
75
|
}
|
|
46
|
-
resolvedPath =
|
|
76
|
+
resolvedPath = import_node_path.default.normalize(resolvedPath);
|
|
47
77
|
return fileList.find((file) => {
|
|
48
|
-
const normalizedFile =
|
|
78
|
+
const normalizedFile = import_node_path.default.normalize(file);
|
|
49
79
|
const fileWithoutExt = normalizedFile.replace(/\.[^/.]+$/, "");
|
|
50
80
|
return normalizedFile === resolvedPath || fileWithoutExt === resolvedPath || normalizedFile === resolvedPath + ".ts" || normalizedFile === resolvedPath + ".js";
|
|
51
81
|
});
|
|
52
82
|
}
|
|
53
83
|
async moduleLinker(specifier, referencingModule) {
|
|
54
|
-
const dbFiles =
|
|
84
|
+
const dbFiles = import_node_fs.default.readdirSync(this.DATABASE_DIR).filter((f) => f.endsWith(".ts")).map((f) => import_node_path.default.join(this.DATABASE_DIR, f));
|
|
55
85
|
const dbResult = this.resolvePath(dbFiles, specifier);
|
|
56
86
|
if (dbResult) {
|
|
57
87
|
try {
|
|
58
88
|
const actualModule = await import(dbResult);
|
|
59
89
|
const exportNames = Object.keys(actualModule);
|
|
60
|
-
return new
|
|
61
|
-
exportNames
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
90
|
+
return new import_node_vm.default.SyntheticModule(
|
|
91
|
+
exportNames,
|
|
92
|
+
function() {
|
|
93
|
+
exportNames.forEach((key) => {
|
|
94
|
+
this.setExport(key, actualModule[key]);
|
|
95
|
+
});
|
|
96
|
+
},
|
|
97
|
+
{ identifier: specifier, context: referencingModule.context }
|
|
98
|
+
);
|
|
65
99
|
} catch (err) {
|
|
66
100
|
console.error(`Failed to load database module ${specifier}:`, err);
|
|
67
101
|
throw err;
|
|
@@ -70,14 +104,18 @@ class VM {
|
|
|
70
104
|
const allowedPackages = Object.keys(this.pkgScriptDB.dependencies || {});
|
|
71
105
|
if (allowedPackages.includes(specifier)) {
|
|
72
106
|
try {
|
|
73
|
-
const modulePath =
|
|
107
|
+
const modulePath = import_node_path.default.join(this.SCRIPTDB_DIR, "node_modules", specifier);
|
|
74
108
|
const actualModule = await import(modulePath);
|
|
75
109
|
const exportNames = Object.keys(actualModule);
|
|
76
|
-
return new
|
|
77
|
-
exportNames
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
110
|
+
return new import_node_vm.default.SyntheticModule(
|
|
111
|
+
exportNames,
|
|
112
|
+
function() {
|
|
113
|
+
exportNames.forEach((key) => {
|
|
114
|
+
this.setExport(key, actualModule[key]);
|
|
115
|
+
});
|
|
116
|
+
},
|
|
117
|
+
{ identifier: specifier, context: referencingModule.context }
|
|
118
|
+
);
|
|
81
119
|
} catch (err) {
|
|
82
120
|
console.error(`Failed to load workspace module ${specifier}:`, err);
|
|
83
121
|
throw err;
|
|
@@ -95,7 +133,7 @@ class VM {
|
|
|
95
133
|
console: customConsole
|
|
96
134
|
});
|
|
97
135
|
const js = this.transpiler.transformSync(code);
|
|
98
|
-
const mod = new
|
|
136
|
+
const mod = new import_node_vm.default.SourceTextModule(js, { context: this.ctx, identifier: import_node_path.default.join(this.SCRIPTDB_DIR, "virtual-entry.js") });
|
|
99
137
|
await mod.link(this.moduleLinker.bind(this));
|
|
100
138
|
await mod.evaluate();
|
|
101
139
|
return {
|
|
@@ -103,9 +141,10 @@ class VM {
|
|
|
103
141
|
logs
|
|
104
142
|
};
|
|
105
143
|
}
|
|
106
|
-
}
|
|
107
|
-
var src_default = VM;
|
|
108
|
-
export {
|
|
109
|
-
src_default as default,
|
|
110
|
-
VM
|
|
111
144
|
};
|
|
145
|
+
var index_default = VM;
|
|
146
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
147
|
+
0 && (module.exports = {
|
|
148
|
+
VM
|
|
149
|
+
});
|
|
150
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import Bun from \"bun\";\nimport vm from \"node:vm\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\ninterface VMOptions {\n language?: 'ts' | 'js';\n registerModules?: { [key: string]: any };\n}\n\nexport class VM {\n private transpiler: Bun.Transpiler;\n private ctx: vm.Context;\n private registerModules: { [key: string]: any };\n private DATABASE_DIR = path.join(os.homedir(), '.scriptdb', 'databases');\n private SCRIPTDB_DIR = path.join(os.homedir(), '.scriptdb');\n private pkgScriptDB: { dependencies?: Record<string, string> } = {};\n constructor(options?: VMOptions) {\n // Ensure directories exist\n if (!fs.existsSync(this.DATABASE_DIR)) {\n fs.mkdirSync(this.DATABASE_DIR, { recursive: true });\n }\n if (!fs.existsSync(this.SCRIPTDB_DIR)) {\n fs.mkdirSync(this.SCRIPTDB_DIR, { recursive: true });\n }\n\n // Load scriptdb workspace package.json if it exists\n const pkgPath = path.join(this.SCRIPTDB_DIR, 'package.json');\n if (fs.existsSync(pkgPath)) {\n this.pkgScriptDB = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));\n }\n this.transpiler = new Bun.Transpiler({\n loader: options?.language || 'ts',\n });\n\n\n\n this.registerModules = options?.registerModules || {};\n\n this.ctx = vm.createContext(this.registerModules);\n\n\n }\n\n register(context: { [key: string]: any }) {\n this.registerModules = { ...this.registerModules, ...context };\n // Register any custom modules or plugins here if needed\n this.ctx = vm.createContext(this.registerModules);\n }\n\n resolvePath(fileList: any[], query: string) {\n const aliases = { '@db': this.DATABASE_DIR };\n \n let resolvedPath = query;\n for (const [alias, target] of Object.entries(aliases)) {\n if (resolvedPath.startsWith(alias + '/')) {\n resolvedPath = resolvedPath.replace(alias, target);\n break;\n }\n }\n\n // Normalize path separators for cross-platform compatibility\n resolvedPath = path.normalize(resolvedPath);\n\n return fileList.find(file => {\n const normalizedFile = path.normalize(file);\n const fileWithoutExt = normalizedFile.replace(/\\.[^/.]+$/, \"\");\n return normalizedFile === resolvedPath || \n fileWithoutExt === resolvedPath || \n normalizedFile === resolvedPath + '.ts' || \n normalizedFile === resolvedPath + '.js';\n });\n }\n\n async moduleLinker(specifier: any, referencingModule: any) {\n // Try database files first\n const dbFiles = fs.readdirSync(this.DATABASE_DIR)\n .filter(f => f.endsWith(\".ts\"))\n .map(f => path.join(this.DATABASE_DIR, f));\n\n const dbResult = this.resolvePath(dbFiles, specifier);\n if (dbResult) {\n try {\n const actualModule = await import(dbResult);\n const exportNames = Object.keys(actualModule);\n return new vm.SyntheticModule(\n exportNames,\n function () {\n exportNames.forEach(key => {\n this.setExport(key, actualModule[key]);\n });\n },\n { identifier: specifier, context: referencingModule.context }\n );\n } catch (err) {\n console.error(`Failed to load database module ${specifier}:`, err);\n throw err;\n }\n }\n\n // Try workspace packages\n const allowedPackages = Object.keys(this.pkgScriptDB.dependencies || {});\n if (allowedPackages.includes(specifier)) {\n try {\n // Import from scriptdb workspace node_modules\n const modulePath = path.join(this.SCRIPTDB_DIR, 'node_modules', specifier);\n const actualModule = await import(modulePath);\n const exportNames = Object.keys(actualModule);\n return new vm.SyntheticModule(\n exportNames,\n function () {\n exportNames.forEach(key => {\n this.setExport(key, actualModule[key]);\n });\n },\n { identifier: specifier, context: referencingModule.context }\n );\n } catch (err) {\n console.error(`Failed to load workspace module ${specifier}:`, err);\n throw err;\n }\n }\n\n throw new Error(`Module ${specifier} is not allowed or not found.`);\n }\n\n async run(code: string, options?: vm.RunningCodeOptions | string) {\n // Remove import statements since modules are already registered in context\n // import { testdb } from 'testdb' -> testdb is already available in this.ctx\n // const importRegex = /^\\s*import\\s+\\{?\\s*([^}]+?)\\s*\\}?\\s+from\\s+['\"]([^'\"]+)['\"]\\s*;?\\s*$/gm;\n // const importMatches = code.match(importRegex);\n // const importCode = importMatches ? importMatches.join('\\n') : '';\n\n\n // const codeWithoutImports = code.replace(importRegex, '').trim();\n\n // // Wrap code in async function\n // const wrappedCode = `(async () => {\\n${codeWithoutImports}\\n})()`;\n\n const logs: any[] = [];\n\n const customConsole = ['log', 'error', 'warn', 'info', 'debug', 'trace'].reduce((acc: any, type: any) => {\n acc[type] = (...args: any[]) => logs.push({ type, args });\n return acc;\n }, {});\n\n this.register({\n console: customConsole\n });\n\n\n const js = this.transpiler.transformSync(code);\n const mod = new vm.SourceTextModule(js, { context: this.ctx, identifier: path.join(this.SCRIPTDB_DIR, 'virtual-entry.js') });\n await mod.link(this.moduleLinker.bind(this));\n await mod.evaluate();\n\n return {\n namespace: mod.namespace,\n logs: logs\n }\n }\n}\n\n\nexport default VM;"],"mappings":"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","names":["path","os","fs","Bun","vm"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import Bun from "bun";
|
|
3
|
+
import vm from "vm";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import os from "os";
|
|
7
|
+
var VM = class {
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.DATABASE_DIR = path.join(os.homedir(), ".scriptdb", "databases");
|
|
10
|
+
this.SCRIPTDB_DIR = path.join(os.homedir(), ".scriptdb");
|
|
11
|
+
this.pkgScriptDB = {};
|
|
12
|
+
if (!fs.existsSync(this.DATABASE_DIR)) {
|
|
13
|
+
fs.mkdirSync(this.DATABASE_DIR, { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
if (!fs.existsSync(this.SCRIPTDB_DIR)) {
|
|
16
|
+
fs.mkdirSync(this.SCRIPTDB_DIR, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
const pkgPath = path.join(this.SCRIPTDB_DIR, "package.json");
|
|
19
|
+
if (fs.existsSync(pkgPath)) {
|
|
20
|
+
this.pkgScriptDB = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
21
|
+
}
|
|
22
|
+
this.transpiler = new Bun.Transpiler({
|
|
23
|
+
loader: options?.language || "ts"
|
|
24
|
+
});
|
|
25
|
+
this.registerModules = options?.registerModules || {};
|
|
26
|
+
this.ctx = vm.createContext(this.registerModules);
|
|
27
|
+
}
|
|
28
|
+
register(context) {
|
|
29
|
+
this.registerModules = { ...this.registerModules, ...context };
|
|
30
|
+
this.ctx = vm.createContext(this.registerModules);
|
|
31
|
+
}
|
|
32
|
+
resolvePath(fileList, query) {
|
|
33
|
+
const aliases = { "@db": this.DATABASE_DIR };
|
|
34
|
+
let resolvedPath = query;
|
|
35
|
+
for (const [alias, target] of Object.entries(aliases)) {
|
|
36
|
+
if (resolvedPath.startsWith(alias + "/")) {
|
|
37
|
+
resolvedPath = resolvedPath.replace(alias, target);
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
resolvedPath = path.normalize(resolvedPath);
|
|
42
|
+
return fileList.find((file) => {
|
|
43
|
+
const normalizedFile = path.normalize(file);
|
|
44
|
+
const fileWithoutExt = normalizedFile.replace(/\.[^/.]+$/, "");
|
|
45
|
+
return normalizedFile === resolvedPath || fileWithoutExt === resolvedPath || normalizedFile === resolvedPath + ".ts" || normalizedFile === resolvedPath + ".js";
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
async moduleLinker(specifier, referencingModule) {
|
|
49
|
+
const dbFiles = fs.readdirSync(this.DATABASE_DIR).filter((f) => f.endsWith(".ts")).map((f) => path.join(this.DATABASE_DIR, f));
|
|
50
|
+
const dbResult = this.resolvePath(dbFiles, specifier);
|
|
51
|
+
if (dbResult) {
|
|
52
|
+
try {
|
|
53
|
+
const actualModule = await import(dbResult);
|
|
54
|
+
const exportNames = Object.keys(actualModule);
|
|
55
|
+
return new vm.SyntheticModule(
|
|
56
|
+
exportNames,
|
|
57
|
+
function() {
|
|
58
|
+
exportNames.forEach((key) => {
|
|
59
|
+
this.setExport(key, actualModule[key]);
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
{ identifier: specifier, context: referencingModule.context }
|
|
63
|
+
);
|
|
64
|
+
} catch (err) {
|
|
65
|
+
console.error(`Failed to load database module ${specifier}:`, err);
|
|
66
|
+
throw err;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const allowedPackages = Object.keys(this.pkgScriptDB.dependencies || {});
|
|
70
|
+
if (allowedPackages.includes(specifier)) {
|
|
71
|
+
try {
|
|
72
|
+
const modulePath = path.join(this.SCRIPTDB_DIR, "node_modules", specifier);
|
|
73
|
+
const actualModule = await import(modulePath);
|
|
74
|
+
const exportNames = Object.keys(actualModule);
|
|
75
|
+
return new vm.SyntheticModule(
|
|
76
|
+
exportNames,
|
|
77
|
+
function() {
|
|
78
|
+
exportNames.forEach((key) => {
|
|
79
|
+
this.setExport(key, actualModule[key]);
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
{ identifier: specifier, context: referencingModule.context }
|
|
83
|
+
);
|
|
84
|
+
} catch (err) {
|
|
85
|
+
console.error(`Failed to load workspace module ${specifier}:`, err);
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`Module ${specifier} is not allowed or not found.`);
|
|
90
|
+
}
|
|
91
|
+
async run(code, options) {
|
|
92
|
+
const logs = [];
|
|
93
|
+
const customConsole = ["log", "error", "warn", "info", "debug", "trace"].reduce((acc, type) => {
|
|
94
|
+
acc[type] = (...args) => logs.push({ type, args });
|
|
95
|
+
return acc;
|
|
96
|
+
}, {});
|
|
97
|
+
this.register({
|
|
98
|
+
console: customConsole
|
|
99
|
+
});
|
|
100
|
+
const js = this.transpiler.transformSync(code);
|
|
101
|
+
const mod = new vm.SourceTextModule(js, { context: this.ctx, identifier: path.join(this.SCRIPTDB_DIR, "virtual-entry.js") });
|
|
102
|
+
await mod.link(this.moduleLinker.bind(this));
|
|
103
|
+
await mod.evaluate();
|
|
104
|
+
return {
|
|
105
|
+
namespace: mod.namespace,
|
|
106
|
+
logs
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
var index_default = VM;
|
|
111
|
+
export {
|
|
112
|
+
VM,
|
|
113
|
+
index_default as default
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import Bun from \"bun\";\nimport vm from \"node:vm\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\ninterface VMOptions {\n language?: 'ts' | 'js';\n registerModules?: { [key: string]: any };\n}\n\nexport class VM {\n private transpiler: Bun.Transpiler;\n private ctx: vm.Context;\n private registerModules: { [key: string]: any };\n private DATABASE_DIR = path.join(os.homedir(), '.scriptdb', 'databases');\n private SCRIPTDB_DIR = path.join(os.homedir(), '.scriptdb');\n private pkgScriptDB: { dependencies?: Record<string, string> } = {};\n constructor(options?: VMOptions) {\n // Ensure directories exist\n if (!fs.existsSync(this.DATABASE_DIR)) {\n fs.mkdirSync(this.DATABASE_DIR, { recursive: true });\n }\n if (!fs.existsSync(this.SCRIPTDB_DIR)) {\n fs.mkdirSync(this.SCRIPTDB_DIR, { recursive: true });\n }\n\n // Load scriptdb workspace package.json if it exists\n const pkgPath = path.join(this.SCRIPTDB_DIR, 'package.json');\n if (fs.existsSync(pkgPath)) {\n this.pkgScriptDB = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));\n }\n this.transpiler = new Bun.Transpiler({\n loader: options?.language || 'ts',\n });\n\n\n\n this.registerModules = options?.registerModules || {};\n\n this.ctx = vm.createContext(this.registerModules);\n\n\n }\n\n register(context: { [key: string]: any }) {\n this.registerModules = { ...this.registerModules, ...context };\n // Register any custom modules or plugins here if needed\n this.ctx = vm.createContext(this.registerModules);\n }\n\n resolvePath(fileList: any[], query: string) {\n const aliases = { '@db': this.DATABASE_DIR };\n \n let resolvedPath = query;\n for (const [alias, target] of Object.entries(aliases)) {\n if (resolvedPath.startsWith(alias + '/')) {\n resolvedPath = resolvedPath.replace(alias, target);\n break;\n }\n }\n\n // Normalize path separators for cross-platform compatibility\n resolvedPath = path.normalize(resolvedPath);\n\n return fileList.find(file => {\n const normalizedFile = path.normalize(file);\n const fileWithoutExt = normalizedFile.replace(/\\.[^/.]+$/, \"\");\n return normalizedFile === resolvedPath || \n fileWithoutExt === resolvedPath || \n normalizedFile === resolvedPath + '.ts' || \n normalizedFile === resolvedPath + '.js';\n });\n }\n\n async moduleLinker(specifier: any, referencingModule: any) {\n // Try database files first\n const dbFiles = fs.readdirSync(this.DATABASE_DIR)\n .filter(f => f.endsWith(\".ts\"))\n .map(f => path.join(this.DATABASE_DIR, f));\n\n const dbResult = this.resolvePath(dbFiles, specifier);\n if (dbResult) {\n try {\n const actualModule = await import(dbResult);\n const exportNames = Object.keys(actualModule);\n return new vm.SyntheticModule(\n exportNames,\n function () {\n exportNames.forEach(key => {\n this.setExport(key, actualModule[key]);\n });\n },\n { identifier: specifier, context: referencingModule.context }\n );\n } catch (err) {\n console.error(`Failed to load database module ${specifier}:`, err);\n throw err;\n }\n }\n\n // Try workspace packages\n const allowedPackages = Object.keys(this.pkgScriptDB.dependencies || {});\n if (allowedPackages.includes(specifier)) {\n try {\n // Import from scriptdb workspace node_modules\n const modulePath = path.join(this.SCRIPTDB_DIR, 'node_modules', specifier);\n const actualModule = await import(modulePath);\n const exportNames = Object.keys(actualModule);\n return new vm.SyntheticModule(\n exportNames,\n function () {\n exportNames.forEach(key => {\n this.setExport(key, actualModule[key]);\n });\n },\n { identifier: specifier, context: referencingModule.context }\n );\n } catch (err) {\n console.error(`Failed to load workspace module ${specifier}:`, err);\n throw err;\n }\n }\n\n throw new Error(`Module ${specifier} is not allowed or not found.`);\n }\n\n async run(code: string, options?: vm.RunningCodeOptions | string) {\n // Remove import statements since modules are already registered in context\n // import { testdb } from 'testdb' -> testdb is already available in this.ctx\n // const importRegex = /^\\s*import\\s+\\{?\\s*([^}]+?)\\s*\\}?\\s+from\\s+['\"]([^'\"]+)['\"]\\s*;?\\s*$/gm;\n // const importMatches = code.match(importRegex);\n // const importCode = importMatches ? importMatches.join('\\n') : '';\n\n\n // const codeWithoutImports = code.replace(importRegex, '').trim();\n\n // // Wrap code in async function\n // const wrappedCode = `(async () => {\\n${codeWithoutImports}\\n})()`;\n\n const logs: any[] = [];\n\n const customConsole = ['log', 'error', 'warn', 'info', 'debug', 'trace'].reduce((acc: any, type: any) => {\n acc[type] = (...args: any[]) => logs.push({ type, args });\n return acc;\n }, {});\n\n this.register({\n console: customConsole\n });\n\n\n const js = this.transpiler.transformSync(code);\n const mod = new vm.SourceTextModule(js, { context: this.ctx, identifier: path.join(this.SCRIPTDB_DIR, 'virtual-entry.js') });\n await mod.link(this.moduleLinker.bind(this));\n await mod.evaluate();\n\n return {\n namespace: mod.namespace,\n logs: logs\n }\n }\n}\n\n\nexport default VM;"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scriptdb/vm",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Virtual machine package for script database",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -17,10 +17,7 @@
|
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
19
|
"dev": "bun --watch src/index.ts",
|
|
20
|
-
"build": "
|
|
21
|
-
"build:cjs": "bun build src/index.ts --outdir dist --target bun --format cjs --outfile dist/index.js",
|
|
22
|
-
"build:types": "tsc --emitDeclarationOnly --project tsconfig.build.json",
|
|
23
|
-
"build:all": "bun run build && bun run build:cjs && bun run build:types",
|
|
20
|
+
"build": "tsup",
|
|
24
21
|
"test": "bun test",
|
|
25
22
|
"lint": "bun run lint:src",
|
|
26
23
|
"lint:src": "eslint src --ext .ts,.tsx",
|