@sandboxxjs/core 0.1.0 → 0.2.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.d.ts +176 -75
- package/dist/index.js +824 -179
- package/dist/index.js.map +11 -9
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -7234,119 +7234,58 @@ class FileSystemError extends SandboxError {
|
|
|
7234
7234
|
// src/isolators/LocalIsolator.ts
|
|
7235
7235
|
class LocalIsolator extends Isolator {
|
|
7236
7236
|
workDir;
|
|
7237
|
-
|
|
7238
|
-
constructor(runtime = "node") {
|
|
7237
|
+
constructor() {
|
|
7239
7238
|
super();
|
|
7240
|
-
this.runtime = runtime;
|
|
7241
7239
|
this.workDir = path6.join(process.cwd(), ".sandbox", `session-${Date.now()}`);
|
|
7242
7240
|
}
|
|
7243
|
-
async
|
|
7244
|
-
const {
|
|
7241
|
+
async shell(command, options = {}) {
|
|
7242
|
+
const { timeout = 30000, env = {} } = options;
|
|
7245
7243
|
const startTime = Date.now();
|
|
7246
7244
|
await fs.mkdir(this.workDir, { recursive: true });
|
|
7247
7245
|
try {
|
|
7248
|
-
const
|
|
7249
|
-
const result = await execa(command[0], command.slice(1), {
|
|
7246
|
+
const result = await execa("sh", ["-c", command], {
|
|
7250
7247
|
cwd: this.workDir,
|
|
7251
7248
|
env: { ...process.env, ...env },
|
|
7252
7249
|
timeout,
|
|
7253
7250
|
maxBuffer: 10 * 1024 * 1024,
|
|
7254
|
-
reject:
|
|
7251
|
+
reject: false,
|
|
7255
7252
|
all: true
|
|
7256
7253
|
});
|
|
7257
7254
|
return {
|
|
7258
7255
|
success: result.exitCode === 0,
|
|
7259
|
-
stdout: result.stdout,
|
|
7260
|
-
stderr: result.stderr,
|
|
7261
|
-
exitCode: result.exitCode
|
|
7262
|
-
|
|
7263
|
-
executionTime: Date.now() - startTime,
|
|
7264
|
-
timestamp: new Date().toISOString()
|
|
7265
|
-
}
|
|
7256
|
+
stdout: result.stdout || "",
|
|
7257
|
+
stderr: result.stderr || "",
|
|
7258
|
+
exitCode: result.exitCode ?? 0,
|
|
7259
|
+
executionTime: Date.now() - startTime
|
|
7266
7260
|
};
|
|
7267
7261
|
} catch (error) {
|
|
7268
|
-
if (error.timedOut) {
|
|
7262
|
+
if (error && typeof error === "object" && "timedOut" in error && error.timedOut) {
|
|
7269
7263
|
throw new TimeoutError(`Execution timed out after ${timeout}ms`);
|
|
7270
7264
|
}
|
|
7271
|
-
|
|
7272
|
-
return {
|
|
7273
|
-
success: false,
|
|
7274
|
-
stdout: error.stdout || "",
|
|
7275
|
-
stderr: error.stderr || "",
|
|
7276
|
-
exitCode: error.exitCode,
|
|
7277
|
-
metadata: {
|
|
7278
|
-
executionTime: Date.now() - startTime,
|
|
7279
|
-
timestamp: new Date().toISOString()
|
|
7280
|
-
}
|
|
7281
|
-
};
|
|
7282
|
-
}
|
|
7283
|
-
throw new ExecutionError(`Execution failed: ${error.message}`);
|
|
7265
|
+
throw new ExecutionError(`Shell execution failed: ${error.message}`);
|
|
7284
7266
|
}
|
|
7285
7267
|
}
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
return ["bash", "-c", code];
|
|
7294
|
-
default:
|
|
7295
|
-
throw new ExecutionError(`Unsupported runtime: ${this.runtime}`);
|
|
7268
|
+
async upload(data, remotePath) {
|
|
7269
|
+
try {
|
|
7270
|
+
const fullPath = path6.join(this.workDir, remotePath);
|
|
7271
|
+
await fs.mkdir(path6.dirname(fullPath), { recursive: true });
|
|
7272
|
+
await fs.writeFile(fullPath, data);
|
|
7273
|
+
} catch (error) {
|
|
7274
|
+
throw new FileSystemError(`Failed to upload file: ${error.message}`);
|
|
7296
7275
|
}
|
|
7297
7276
|
}
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
|
|
7301
|
-
|
|
7302
|
-
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
} catch (error) {
|
|
7306
|
-
throw new FileSystemError(`Failed to write file: ${error.message}`);
|
|
7307
|
-
}
|
|
7308
|
-
},
|
|
7309
|
-
read: async (filePath) => {
|
|
7310
|
-
try {
|
|
7311
|
-
const fullPath = path6.join(this.workDir, filePath);
|
|
7312
|
-
return await fs.readFile(fullPath, "utf-8");
|
|
7313
|
-
} catch (error) {
|
|
7314
|
-
throw new FileSystemError(`Failed to read file: ${error.message}`);
|
|
7315
|
-
}
|
|
7316
|
-
},
|
|
7317
|
-
list: async (dirPath) => {
|
|
7318
|
-
try {
|
|
7319
|
-
const fullPath = path6.join(this.workDir, dirPath);
|
|
7320
|
-
return await fs.readdir(fullPath);
|
|
7321
|
-
} catch (error) {
|
|
7322
|
-
throw new FileSystemError(`Failed to list directory: ${error.message}`);
|
|
7323
|
-
}
|
|
7324
|
-
},
|
|
7325
|
-
delete: async (filePath) => {
|
|
7326
|
-
try {
|
|
7327
|
-
const fullPath = path6.join(this.workDir, filePath);
|
|
7328
|
-
await fs.rm(fullPath, { recursive: true, force: true });
|
|
7329
|
-
} catch (error) {
|
|
7330
|
-
throw new FileSystemError(`Failed to delete: ${error.message}`);
|
|
7331
|
-
}
|
|
7332
|
-
},
|
|
7333
|
-
exists: async (filePath) => {
|
|
7334
|
-
try {
|
|
7335
|
-
const fullPath = path6.join(this.workDir, filePath);
|
|
7336
|
-
await fs.access(fullPath);
|
|
7337
|
-
return true;
|
|
7338
|
-
} catch {
|
|
7339
|
-
return false;
|
|
7340
|
-
}
|
|
7341
|
-
}
|
|
7342
|
-
};
|
|
7277
|
+
async download(remotePath) {
|
|
7278
|
+
try {
|
|
7279
|
+
const fullPath = path6.join(this.workDir, remotePath);
|
|
7280
|
+
return await fs.readFile(fullPath);
|
|
7281
|
+
} catch (error) {
|
|
7282
|
+
throw new FileSystemError(`Failed to download file: ${error.message}`);
|
|
7283
|
+
}
|
|
7343
7284
|
}
|
|
7344
7285
|
async destroy() {
|
|
7345
7286
|
try {
|
|
7346
7287
|
await fs.rm(this.workDir, { recursive: true, force: true });
|
|
7347
|
-
} catch
|
|
7348
|
-
console.warn(`Failed to clean up work directory: ${error.message}`);
|
|
7349
|
-
}
|
|
7288
|
+
} catch {}
|
|
7350
7289
|
}
|
|
7351
7290
|
}
|
|
7352
7291
|
|
|
@@ -7360,10 +7299,8 @@ class CloudflareContainerIsolator extends Isolator {
|
|
|
7360
7299
|
serverProcess;
|
|
7361
7300
|
serverUrl;
|
|
7362
7301
|
isReady = false;
|
|
7363
|
-
|
|
7364
|
-
constructor(runtime = "node") {
|
|
7302
|
+
constructor() {
|
|
7365
7303
|
super();
|
|
7366
|
-
this.runtime = runtime;
|
|
7367
7304
|
}
|
|
7368
7305
|
async findFreePort() {
|
|
7369
7306
|
return new Promise((resolve, reject) => {
|
|
@@ -7411,17 +7348,19 @@ class CloudflareContainerIsolator extends Isolator {
|
|
|
7411
7348
|
await this.waitForReady(this.serverUrl);
|
|
7412
7349
|
this.isReady = true;
|
|
7413
7350
|
}
|
|
7414
|
-
async
|
|
7351
|
+
async shell(command, options = {}) {
|
|
7352
|
+
const { timeout = 30000, env = {} } = options;
|
|
7353
|
+
const startTime = Date.now();
|
|
7415
7354
|
await this.ensureServerRunning();
|
|
7416
7355
|
try {
|
|
7417
7356
|
const response = await fetch(`${this.serverUrl}/execute`, {
|
|
7418
7357
|
method: "POST",
|
|
7419
7358
|
headers: { "Content-Type": "application/json" },
|
|
7420
7359
|
body: JSON.stringify({
|
|
7421
|
-
code:
|
|
7422
|
-
runtime:
|
|
7423
|
-
env
|
|
7424
|
-
timeout
|
|
7360
|
+
code: command,
|
|
7361
|
+
runtime: "bash",
|
|
7362
|
+
env,
|
|
7363
|
+
timeout
|
|
7425
7364
|
})
|
|
7426
7365
|
});
|
|
7427
7366
|
if (!response.ok) {
|
|
@@ -7429,29 +7368,22 @@ class CloudflareContainerIsolator extends Isolator {
|
|
|
7429
7368
|
throw new ExecutionError(`Server execution failed: ${error}`);
|
|
7430
7369
|
}
|
|
7431
7370
|
const result = await response.json();
|
|
7432
|
-
return
|
|
7371
|
+
return {
|
|
7372
|
+
success: result.success,
|
|
7373
|
+
stdout: result.stdout || "",
|
|
7374
|
+
stderr: result.stderr || "",
|
|
7375
|
+
exitCode: result.exitCode ?? (result.success ? 0 : 1),
|
|
7376
|
+
executionTime: Date.now() - startTime
|
|
7377
|
+
};
|
|
7433
7378
|
} catch (error) {
|
|
7434
|
-
throw new ExecutionError(`
|
|
7379
|
+
throw new ExecutionError(`Shell execution failed: ${error.message}`);
|
|
7435
7380
|
}
|
|
7436
7381
|
}
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
read: async () => {
|
|
7443
|
-
throw new FileSystemError("Filesystem not yet implemented for CloudflareContainerIsolator");
|
|
7444
|
-
},
|
|
7445
|
-
list: async () => {
|
|
7446
|
-
throw new FileSystemError("Filesystem not yet implemented for CloudflareContainerIsolator");
|
|
7447
|
-
},
|
|
7448
|
-
delete: async () => {
|
|
7449
|
-
throw new FileSystemError("Filesystem not yet implemented for CloudflareContainerIsolator");
|
|
7450
|
-
},
|
|
7451
|
-
exists: async () => {
|
|
7452
|
-
throw new FileSystemError("Filesystem not yet implemented for CloudflareContainerIsolator");
|
|
7453
|
-
}
|
|
7454
|
-
};
|
|
7382
|
+
async upload(_data, _remotePath) {
|
|
7383
|
+
throw new FileSystemError("Upload not yet implemented for CloudflareContainerIsolator");
|
|
7384
|
+
}
|
|
7385
|
+
async download(_remotePath) {
|
|
7386
|
+
throw new FileSystemError("Download not yet implemented for CloudflareContainerIsolator");
|
|
7455
7387
|
}
|
|
7456
7388
|
async destroy() {
|
|
7457
7389
|
if (this.serverProcess) {
|
|
@@ -7463,103 +7395,816 @@ class CloudflareContainerIsolator extends Isolator {
|
|
|
7463
7395
|
}
|
|
7464
7396
|
}
|
|
7465
7397
|
|
|
7466
|
-
// src/runtimes/Runtime.ts
|
|
7467
|
-
class Runtime {
|
|
7468
|
-
}
|
|
7469
|
-
|
|
7470
|
-
// src/runtimes/GenericRuntime.ts
|
|
7471
|
-
class GenericRuntime extends Runtime {
|
|
7472
|
-
isolator;
|
|
7473
|
-
constructor(isolator) {
|
|
7474
|
-
super();
|
|
7475
|
-
this.isolator = isolator;
|
|
7476
|
-
}
|
|
7477
|
-
async execute(options) {
|
|
7478
|
-
return this.isolator.execute(options);
|
|
7479
|
-
}
|
|
7480
|
-
async prepare() {}
|
|
7481
|
-
async cleanup() {}
|
|
7482
|
-
}
|
|
7483
|
-
|
|
7484
7398
|
// src/Sandbox.ts
|
|
7485
|
-
class
|
|
7399
|
+
class BaseSandbox {
|
|
7486
7400
|
isolator;
|
|
7487
|
-
|
|
7488
|
-
eventHandlers = new Map;
|
|
7489
|
-
fs;
|
|
7401
|
+
config;
|
|
7490
7402
|
constructor(config) {
|
|
7491
|
-
this.
|
|
7492
|
-
this.
|
|
7493
|
-
this.runtime = this.createRuntime(config.runtime, this.isolator);
|
|
7403
|
+
this.config = config;
|
|
7404
|
+
this.isolator = this.createIsolator(config.isolator);
|
|
7494
7405
|
}
|
|
7495
|
-
createIsolator(isolatorType
|
|
7406
|
+
createIsolator(isolatorType) {
|
|
7496
7407
|
switch (isolatorType) {
|
|
7497
7408
|
case "local":
|
|
7498
|
-
return new LocalIsolator
|
|
7409
|
+
return new LocalIsolator;
|
|
7499
7410
|
case "cloudflare":
|
|
7500
|
-
return new CloudflareContainerIsolator
|
|
7411
|
+
return new CloudflareContainerIsolator;
|
|
7501
7412
|
case "e2b":
|
|
7502
|
-
case "firecracker":
|
|
7503
7413
|
case "docker":
|
|
7504
7414
|
throw new SandboxError(`Isolator "${isolatorType}" not yet implemented`);
|
|
7505
7415
|
default:
|
|
7506
7416
|
throw new SandboxError(`Unknown isolator type: ${isolatorType}`);
|
|
7507
7417
|
}
|
|
7508
7418
|
}
|
|
7509
|
-
|
|
7510
|
-
return
|
|
7419
|
+
async shell(command) {
|
|
7420
|
+
return this.isolator.shell(command, {
|
|
7421
|
+
timeout: this.config.limits?.timeout
|
|
7422
|
+
});
|
|
7423
|
+
}
|
|
7424
|
+
async upload(data, remotePath) {
|
|
7425
|
+
return this.isolator.upload(data, remotePath);
|
|
7426
|
+
}
|
|
7427
|
+
async download(remotePath) {
|
|
7428
|
+
return this.isolator.download(remotePath);
|
|
7429
|
+
}
|
|
7430
|
+
async destroy() {
|
|
7431
|
+
return this.isolator.destroy();
|
|
7432
|
+
}
|
|
7433
|
+
}
|
|
7434
|
+
// ../state/dist/index.js
|
|
7435
|
+
import { readFile as readFile2, writeFile as writeFile2, readdir, mkdir as mkdir2, rm as rm2, access, stat as fsStat } from "node:fs/promises";
|
|
7436
|
+
import { resolve, dirname as dirname2 } from "node:path";
|
|
7437
|
+
import { createHash } from "crypto";
|
|
7438
|
+
|
|
7439
|
+
class StateError extends Error {
|
|
7440
|
+
constructor(message) {
|
|
7441
|
+
super(message);
|
|
7442
|
+
this.name = "StateError";
|
|
7511
7443
|
}
|
|
7512
|
-
|
|
7513
|
-
|
|
7444
|
+
}
|
|
7445
|
+
|
|
7446
|
+
class FileSystemError2 extends StateError {
|
|
7447
|
+
constructor(message) {
|
|
7448
|
+
super(message);
|
|
7449
|
+
this.name = "FileSystemError";
|
|
7450
|
+
}
|
|
7451
|
+
}
|
|
7452
|
+
|
|
7453
|
+
class StateFS {
|
|
7454
|
+
sandbox;
|
|
7455
|
+
constructor(sandbox) {
|
|
7456
|
+
this.sandbox = sandbox;
|
|
7457
|
+
}
|
|
7458
|
+
async read(path7) {
|
|
7459
|
+
const result = await this.sandbox.shell(`cat "${path7}"`);
|
|
7460
|
+
if (!result.success) {
|
|
7461
|
+
throw new FileSystemError2(`Failed to read file: ${path7}`);
|
|
7462
|
+
}
|
|
7463
|
+
return result.stdout;
|
|
7464
|
+
}
|
|
7465
|
+
async write(path7, data) {
|
|
7466
|
+
const dir = path7.substring(0, path7.lastIndexOf("/"));
|
|
7467
|
+
if (dir) {
|
|
7468
|
+
await this.sandbox.shell(`mkdir -p "${dir}"`);
|
|
7469
|
+
}
|
|
7470
|
+
const result = await this.sandbox.shell(`cat > "${path7}" << 'SANDBOX_EOF'
|
|
7471
|
+
${data}
|
|
7472
|
+
SANDBOX_EOF`);
|
|
7473
|
+
if (!result.success) {
|
|
7474
|
+
throw new FileSystemError2(`Failed to write file: ${path7}`);
|
|
7475
|
+
}
|
|
7476
|
+
}
|
|
7477
|
+
async exists(path7) {
|
|
7478
|
+
const result = await this.sandbox.shell(`test -e "${path7}" && echo "yes" || echo "no"`);
|
|
7479
|
+
return result.stdout.trim() === "yes";
|
|
7480
|
+
}
|
|
7481
|
+
async delete(path7) {
|
|
7482
|
+
await this.sandbox.shell(`rm -rf "${path7}"`);
|
|
7483
|
+
}
|
|
7484
|
+
async list(path7) {
|
|
7485
|
+
const result = await this.sandbox.shell(`ls -1 "${path7}" 2>/dev/null`);
|
|
7486
|
+
if (!result.success || !result.stdout.trim()) {
|
|
7487
|
+
return [];
|
|
7488
|
+
}
|
|
7489
|
+
return result.stdout.trim().split(`
|
|
7490
|
+
`).filter(Boolean);
|
|
7491
|
+
}
|
|
7492
|
+
}
|
|
7493
|
+
|
|
7494
|
+
class StateEnv {
|
|
7495
|
+
vars;
|
|
7496
|
+
constructor(initial) {
|
|
7497
|
+
this.vars = new Map(Object.entries(initial ?? {}));
|
|
7498
|
+
}
|
|
7499
|
+
get(key) {
|
|
7500
|
+
return this.vars.get(key);
|
|
7501
|
+
}
|
|
7502
|
+
set(key, value) {
|
|
7503
|
+
this.vars.set(key, value);
|
|
7504
|
+
}
|
|
7505
|
+
has(key) {
|
|
7506
|
+
return this.vars.has(key);
|
|
7507
|
+
}
|
|
7508
|
+
delete(key) {
|
|
7509
|
+
this.vars.delete(key);
|
|
7510
|
+
}
|
|
7511
|
+
keys() {
|
|
7512
|
+
return [...this.vars.keys()];
|
|
7513
|
+
}
|
|
7514
|
+
all() {
|
|
7515
|
+
return Object.fromEntries(this.vars);
|
|
7516
|
+
}
|
|
7517
|
+
}
|
|
7518
|
+
|
|
7519
|
+
class StateStorage {
|
|
7520
|
+
data;
|
|
7521
|
+
constructor(initial) {
|
|
7522
|
+
this.data = new Map(Object.entries(initial ?? {}));
|
|
7523
|
+
}
|
|
7524
|
+
getItem(key) {
|
|
7525
|
+
return this.data.get(key) ?? null;
|
|
7526
|
+
}
|
|
7527
|
+
setItem(key, value) {
|
|
7528
|
+
this.data.set(key, value);
|
|
7529
|
+
}
|
|
7530
|
+
removeItem(key) {
|
|
7531
|
+
this.data.delete(key);
|
|
7532
|
+
}
|
|
7533
|
+
clear() {
|
|
7534
|
+
this.data.clear();
|
|
7535
|
+
}
|
|
7536
|
+
keys() {
|
|
7537
|
+
return [...this.data.keys()];
|
|
7538
|
+
}
|
|
7539
|
+
}
|
|
7540
|
+
|
|
7541
|
+
class StateLog {
|
|
7542
|
+
entries = [];
|
|
7543
|
+
fs = {
|
|
7544
|
+
write: (path7, data) => {
|
|
7545
|
+
this.entries.push({ op: "fs.write", args: { path: path7, data } });
|
|
7546
|
+
return this;
|
|
7547
|
+
},
|
|
7548
|
+
delete: (path7) => {
|
|
7549
|
+
this.entries.push({ op: "fs.delete", args: { path: path7 } });
|
|
7550
|
+
return this;
|
|
7551
|
+
}
|
|
7552
|
+
};
|
|
7553
|
+
env = {
|
|
7554
|
+
set: (key, value) => {
|
|
7555
|
+
this.entries.push({ op: "env.set", args: { key, value } });
|
|
7556
|
+
return this;
|
|
7557
|
+
},
|
|
7558
|
+
delete: (key) => {
|
|
7559
|
+
this.entries.push({ op: "env.delete", args: { key } });
|
|
7560
|
+
return this;
|
|
7561
|
+
}
|
|
7562
|
+
};
|
|
7563
|
+
storage = {
|
|
7564
|
+
set: (key, value) => {
|
|
7565
|
+
this.entries.push({ op: "storage.set", args: { key, value } });
|
|
7566
|
+
return this;
|
|
7567
|
+
},
|
|
7568
|
+
delete: (key) => {
|
|
7569
|
+
this.entries.push({ op: "storage.delete", args: { key } });
|
|
7570
|
+
return this;
|
|
7571
|
+
},
|
|
7572
|
+
clear: () => {
|
|
7573
|
+
this.entries.push({ op: "storage.clear", args: {} });
|
|
7574
|
+
return this;
|
|
7575
|
+
}
|
|
7576
|
+
};
|
|
7577
|
+
recordEntry(op, args) {
|
|
7578
|
+
this.entries.push({ op, args });
|
|
7579
|
+
return this;
|
|
7580
|
+
}
|
|
7581
|
+
getEntries() {
|
|
7582
|
+
return [...this.entries];
|
|
7583
|
+
}
|
|
7584
|
+
toJSON() {
|
|
7585
|
+
return JSON.stringify(this.entries);
|
|
7586
|
+
}
|
|
7587
|
+
static fromJSON(json) {
|
|
7588
|
+
const log = new StateLog;
|
|
7589
|
+
log.entries = JSON.parse(json);
|
|
7590
|
+
return log;
|
|
7591
|
+
}
|
|
7592
|
+
static fromEntries(entries) {
|
|
7593
|
+
const log = new StateLog;
|
|
7594
|
+
log.entries = [...entries];
|
|
7595
|
+
return log;
|
|
7596
|
+
}
|
|
7597
|
+
compact() {
|
|
7598
|
+
const fsState = new Map;
|
|
7599
|
+
const envState = new Map;
|
|
7600
|
+
const storageState = new Map;
|
|
7601
|
+
let storageClear = null;
|
|
7602
|
+
for (const entry of this.entries) {
|
|
7603
|
+
const { op, args } = entry;
|
|
7604
|
+
if (op === "fs.write") {
|
|
7605
|
+
fsState.set(args.path, entry);
|
|
7606
|
+
} else if (op === "fs.delete") {
|
|
7607
|
+
fsState.set(args.path, entry);
|
|
7608
|
+
} else if (op === "env.set") {
|
|
7609
|
+
envState.set(args.key, entry);
|
|
7610
|
+
} else if (op === "env.delete") {
|
|
7611
|
+
envState.set(args.key, entry);
|
|
7612
|
+
} else if (op === "storage.set") {
|
|
7613
|
+
storageState.set(args.key, entry);
|
|
7614
|
+
} else if (op === "storage.delete") {
|
|
7615
|
+
storageState.set(args.key, entry);
|
|
7616
|
+
} else if (op === "storage.clear") {
|
|
7617
|
+
storageClear = entry;
|
|
7618
|
+
storageState.clear();
|
|
7619
|
+
}
|
|
7620
|
+
}
|
|
7621
|
+
const compactedEntries = [];
|
|
7622
|
+
for (const entry of fsState.values()) {
|
|
7623
|
+
compactedEntries.push(entry);
|
|
7624
|
+
}
|
|
7625
|
+
for (const entry of envState.values()) {
|
|
7626
|
+
compactedEntries.push(entry);
|
|
7627
|
+
}
|
|
7628
|
+
if (storageClear) {
|
|
7629
|
+
compactedEntries.push(storageClear);
|
|
7630
|
+
}
|
|
7631
|
+
for (const entry of storageState.values()) {
|
|
7632
|
+
compactedEntries.push(entry);
|
|
7633
|
+
}
|
|
7634
|
+
return StateLog.fromEntries(compactedEntries);
|
|
7635
|
+
}
|
|
7636
|
+
}
|
|
7637
|
+
function buildStateLog() {
|
|
7638
|
+
return new StateLog;
|
|
7639
|
+
}
|
|
7640
|
+
function loadStateLog(json) {
|
|
7641
|
+
return StateLog.fromJSON(json);
|
|
7642
|
+
}
|
|
7643
|
+
var opRegistry = {
|
|
7644
|
+
"fs.write": {
|
|
7645
|
+
namespace: "fs",
|
|
7646
|
+
method: "write",
|
|
7647
|
+
args: ["path", "data"],
|
|
7648
|
+
replay: async (target, args) => {
|
|
7649
|
+
await target.fs.write(args.path, args.data);
|
|
7650
|
+
}
|
|
7651
|
+
},
|
|
7652
|
+
"fs.delete": {
|
|
7653
|
+
namespace: "fs",
|
|
7654
|
+
method: "delete",
|
|
7655
|
+
args: ["path"],
|
|
7656
|
+
replay: async (target, args) => {
|
|
7657
|
+
await target.fs.delete(args.path);
|
|
7658
|
+
}
|
|
7659
|
+
},
|
|
7660
|
+
"env.set": {
|
|
7661
|
+
namespace: "env",
|
|
7662
|
+
method: "set",
|
|
7663
|
+
args: ["key", "value"],
|
|
7664
|
+
replay: (target, args) => {
|
|
7665
|
+
target.env.set(args.key, args.value);
|
|
7666
|
+
}
|
|
7667
|
+
},
|
|
7668
|
+
"env.delete": {
|
|
7669
|
+
namespace: "env",
|
|
7670
|
+
method: "delete",
|
|
7671
|
+
args: ["key"],
|
|
7672
|
+
replay: (target, args) => {
|
|
7673
|
+
target.env.delete(args.key);
|
|
7674
|
+
}
|
|
7675
|
+
},
|
|
7676
|
+
"storage.set": {
|
|
7677
|
+
namespace: "storage",
|
|
7678
|
+
method: "setItem",
|
|
7679
|
+
args: ["key", "value"],
|
|
7680
|
+
replay: (target, args) => {
|
|
7681
|
+
target.storage.setItem(args.key, args.value);
|
|
7682
|
+
}
|
|
7683
|
+
},
|
|
7684
|
+
"storage.delete": {
|
|
7685
|
+
namespace: "storage",
|
|
7686
|
+
method: "removeItem",
|
|
7687
|
+
args: ["key"],
|
|
7688
|
+
replay: (target, args) => {
|
|
7689
|
+
target.storage.removeItem(args.key);
|
|
7690
|
+
}
|
|
7691
|
+
},
|
|
7692
|
+
"storage.clear": {
|
|
7693
|
+
namespace: "storage",
|
|
7694
|
+
method: "clear",
|
|
7695
|
+
args: [],
|
|
7696
|
+
replay: (target) => {
|
|
7697
|
+
target.storage.clear();
|
|
7698
|
+
}
|
|
7699
|
+
}
|
|
7700
|
+
};
|
|
7701
|
+
function findOp(namespace, method) {
|
|
7702
|
+
for (const [op, config] of Object.entries(opRegistry)) {
|
|
7703
|
+
if (config.namespace === namespace && config.method === method) {
|
|
7704
|
+
return op;
|
|
7705
|
+
}
|
|
7706
|
+
}
|
|
7707
|
+
return;
|
|
7708
|
+
}
|
|
7709
|
+
function argsToEntry(op, methodArgs) {
|
|
7710
|
+
const config = opRegistry[op];
|
|
7711
|
+
if (!config)
|
|
7712
|
+
return {};
|
|
7713
|
+
const entry = {};
|
|
7714
|
+
config.args.forEach((name, index) => {
|
|
7715
|
+
entry[name] = methodArgs[index];
|
|
7716
|
+
});
|
|
7717
|
+
return entry;
|
|
7718
|
+
}
|
|
7719
|
+
async function replayStateLog(log, target) {
|
|
7720
|
+
for (const entry of log.getEntries()) {
|
|
7721
|
+
const config = opRegistry[entry.op];
|
|
7722
|
+
if (config) {
|
|
7723
|
+
await config.replay(target, entry.args);
|
|
7724
|
+
}
|
|
7725
|
+
}
|
|
7726
|
+
}
|
|
7727
|
+
function createRecordingProxy(target, namespace, log) {
|
|
7728
|
+
return new Proxy(target, {
|
|
7729
|
+
get(obj, prop) {
|
|
7730
|
+
const value = obj[prop];
|
|
7731
|
+
if (typeof value !== "function") {
|
|
7732
|
+
return value;
|
|
7733
|
+
}
|
|
7734
|
+
const method = prop;
|
|
7735
|
+
const op = findOp(namespace, method);
|
|
7736
|
+
if (!op) {
|
|
7737
|
+
return value.bind(obj);
|
|
7738
|
+
}
|
|
7739
|
+
return (...args) => {
|
|
7740
|
+
const result = value.apply(obj, args);
|
|
7741
|
+
const record = () => {
|
|
7742
|
+
const entryArgs = argsToEntry(op, args);
|
|
7743
|
+
log.recordEntry(op, entryArgs);
|
|
7744
|
+
};
|
|
7745
|
+
if (result instanceof Promise) {
|
|
7746
|
+
return result.then((res) => {
|
|
7747
|
+
record();
|
|
7748
|
+
return res;
|
|
7749
|
+
});
|
|
7750
|
+
} else {
|
|
7751
|
+
record();
|
|
7752
|
+
return result;
|
|
7753
|
+
}
|
|
7754
|
+
};
|
|
7755
|
+
}
|
|
7756
|
+
});
|
|
7757
|
+
}
|
|
7758
|
+
function createState(options) {
|
|
7759
|
+
const { sandbox, env, enableRecord } = options;
|
|
7760
|
+
const baseFS = new StateFS(sandbox);
|
|
7761
|
+
const baseEnv = new StateEnv(env);
|
|
7762
|
+
const baseStorage = new StateStorage;
|
|
7763
|
+
if (!enableRecord) {
|
|
7764
|
+
return {
|
|
7765
|
+
fs: baseFS,
|
|
7766
|
+
env: baseEnv,
|
|
7767
|
+
storage: baseStorage
|
|
7768
|
+
};
|
|
7769
|
+
}
|
|
7770
|
+
const stateLog = buildStateLog();
|
|
7771
|
+
return {
|
|
7772
|
+
fs: createRecordingProxy(baseFS, "fs", stateLog),
|
|
7773
|
+
env: createRecordingProxy(baseEnv, "env", stateLog),
|
|
7774
|
+
storage: createRecordingProxy(baseStorage, "storage", stateLog),
|
|
7775
|
+
stateLog
|
|
7776
|
+
};
|
|
7777
|
+
}
|
|
7778
|
+
|
|
7779
|
+
class ResourceXError extends Error {
|
|
7780
|
+
constructor(message, options) {
|
|
7781
|
+
super(message, options);
|
|
7782
|
+
this.name = "ResourceXError";
|
|
7783
|
+
}
|
|
7784
|
+
}
|
|
7785
|
+
class TransportError extends ResourceXError {
|
|
7786
|
+
transport;
|
|
7787
|
+
constructor(message, transport, options) {
|
|
7788
|
+
super(message, options);
|
|
7789
|
+
this.transport = transport;
|
|
7790
|
+
this.name = "TransportError";
|
|
7791
|
+
}
|
|
7792
|
+
}
|
|
7793
|
+
|
|
7794
|
+
class SemanticError extends ResourceXError {
|
|
7795
|
+
semantic;
|
|
7796
|
+
constructor(message, semantic, options) {
|
|
7797
|
+
super(message, options);
|
|
7798
|
+
this.semantic = semantic;
|
|
7799
|
+
this.name = "SemanticError";
|
|
7800
|
+
}
|
|
7801
|
+
}
|
|
7802
|
+
class HttpTransportHandler {
|
|
7803
|
+
name;
|
|
7804
|
+
protocol;
|
|
7805
|
+
capabilities = {
|
|
7806
|
+
canRead: true,
|
|
7807
|
+
canWrite: false,
|
|
7808
|
+
canList: false,
|
|
7809
|
+
canDelete: false,
|
|
7810
|
+
canStat: false
|
|
7811
|
+
};
|
|
7812
|
+
constructor(protocol = "https") {
|
|
7813
|
+
this.protocol = protocol;
|
|
7814
|
+
this.name = protocol;
|
|
7815
|
+
}
|
|
7816
|
+
async read(location) {
|
|
7817
|
+
const url = `${this.protocol}://${location}`;
|
|
7514
7818
|
try {
|
|
7515
|
-
const
|
|
7516
|
-
|
|
7517
|
-
|
|
7819
|
+
const response = await fetch(url);
|
|
7820
|
+
if (!response.ok) {
|
|
7821
|
+
throw new TransportError(`HTTP ${response.status}: ${response.statusText} - ${url}`, this.name);
|
|
7822
|
+
}
|
|
7823
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
7824
|
+
return Buffer.from(arrayBuffer);
|
|
7518
7825
|
} catch (error) {
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
this.
|
|
7826
|
+
if (error instanceof TransportError) {
|
|
7827
|
+
throw error;
|
|
7828
|
+
}
|
|
7829
|
+
throw new TransportError(`Network error: ${url}`, this.name, {
|
|
7830
|
+
cause: error
|
|
7831
|
+
});
|
|
7523
7832
|
}
|
|
7524
7833
|
}
|
|
7525
|
-
|
|
7526
|
-
|
|
7834
|
+
}
|
|
7835
|
+
var httpsHandler = new HttpTransportHandler("https");
|
|
7836
|
+
var httpHandler = new HttpTransportHandler("http");
|
|
7837
|
+
|
|
7838
|
+
class FileTransportHandler {
|
|
7839
|
+
name = "file";
|
|
7840
|
+
capabilities = {
|
|
7841
|
+
canRead: true,
|
|
7842
|
+
canWrite: true,
|
|
7843
|
+
canList: true,
|
|
7844
|
+
canDelete: true,
|
|
7845
|
+
canStat: true
|
|
7846
|
+
};
|
|
7847
|
+
resolvePath(location) {
|
|
7848
|
+
return resolve(process.cwd(), location);
|
|
7527
7849
|
}
|
|
7528
|
-
async
|
|
7529
|
-
|
|
7850
|
+
async read(location) {
|
|
7851
|
+
const filePath = this.resolvePath(location);
|
|
7852
|
+
try {
|
|
7853
|
+
return await readFile2(filePath);
|
|
7854
|
+
} catch (error) {
|
|
7855
|
+
const err = error;
|
|
7856
|
+
throw new TransportError(`File read error: ${err.code} - ${filePath}`, this.name, {
|
|
7857
|
+
cause: err
|
|
7858
|
+
});
|
|
7859
|
+
}
|
|
7530
7860
|
}
|
|
7531
|
-
async
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7861
|
+
async write(location, content) {
|
|
7862
|
+
const filePath = this.resolvePath(location);
|
|
7863
|
+
try {
|
|
7864
|
+
await mkdir2(dirname2(filePath), { recursive: true });
|
|
7865
|
+
await writeFile2(filePath, content);
|
|
7866
|
+
} catch (error) {
|
|
7867
|
+
const err = error;
|
|
7868
|
+
throw new TransportError(`File write error: ${err.code} - ${filePath}`, this.name, {
|
|
7869
|
+
cause: err
|
|
7870
|
+
});
|
|
7871
|
+
}
|
|
7535
7872
|
}
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7873
|
+
async list(location) {
|
|
7874
|
+
const dirPath = this.resolvePath(location);
|
|
7875
|
+
try {
|
|
7876
|
+
return await readdir(dirPath);
|
|
7877
|
+
} catch (error) {
|
|
7878
|
+
const err = error;
|
|
7879
|
+
throw new TransportError(`Directory list error: ${err.code} - ${dirPath}`, this.name, {
|
|
7880
|
+
cause: err
|
|
7881
|
+
});
|
|
7539
7882
|
}
|
|
7540
|
-
this.eventHandlers.get(event).push(handler);
|
|
7541
7883
|
}
|
|
7542
|
-
|
|
7543
|
-
const
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7884
|
+
async mkdir(location) {
|
|
7885
|
+
const dirPath = this.resolvePath(location);
|
|
7886
|
+
try {
|
|
7887
|
+
await mkdir2(dirPath, { recursive: true });
|
|
7888
|
+
} catch (error) {
|
|
7889
|
+
const err = error;
|
|
7890
|
+
throw new TransportError(`Directory create error: ${err.code} - ${dirPath}`, this.name, {
|
|
7891
|
+
cause: err
|
|
7892
|
+
});
|
|
7893
|
+
}
|
|
7894
|
+
}
|
|
7895
|
+
async exists(location) {
|
|
7896
|
+
const filePath = this.resolvePath(location);
|
|
7897
|
+
try {
|
|
7898
|
+
await access(filePath);
|
|
7899
|
+
return true;
|
|
7900
|
+
} catch {
|
|
7901
|
+
return false;
|
|
7902
|
+
}
|
|
7903
|
+
}
|
|
7904
|
+
async stat(location) {
|
|
7905
|
+
const filePath = this.resolvePath(location);
|
|
7906
|
+
try {
|
|
7907
|
+
const stats = await fsStat(filePath);
|
|
7908
|
+
return {
|
|
7909
|
+
size: stats.size,
|
|
7910
|
+
modifiedAt: stats.mtime,
|
|
7911
|
+
isDirectory: stats.isDirectory()
|
|
7912
|
+
};
|
|
7913
|
+
} catch (error) {
|
|
7914
|
+
const err = error;
|
|
7915
|
+
throw new TransportError(`File stat error: ${err.code} - ${filePath}`, this.name, {
|
|
7916
|
+
cause: err
|
|
7917
|
+
});
|
|
7918
|
+
}
|
|
7919
|
+
}
|
|
7920
|
+
async delete(location) {
|
|
7921
|
+
const filePath = this.resolvePath(location);
|
|
7922
|
+
try {
|
|
7923
|
+
await rm2(filePath, { recursive: true });
|
|
7924
|
+
} catch (error) {
|
|
7925
|
+
const err = error;
|
|
7926
|
+
throw new TransportError(`File delete error: ${err.code} - ${filePath}`, this.name, {
|
|
7927
|
+
cause: err
|
|
7928
|
+
});
|
|
7929
|
+
}
|
|
7930
|
+
}
|
|
7931
|
+
}
|
|
7932
|
+
var fileHandler = new FileTransportHandler;
|
|
7933
|
+
var handlers = new Map([
|
|
7934
|
+
["https", httpsHandler],
|
|
7935
|
+
["http", httpHandler],
|
|
7936
|
+
["file", fileHandler]
|
|
7937
|
+
]);
|
|
7938
|
+
class TextSemanticHandler {
|
|
7939
|
+
name = "text";
|
|
7940
|
+
async resolve(transport, location, context) {
|
|
7941
|
+
const buffer = await transport.read(location);
|
|
7942
|
+
const text = buffer.toString("utf-8");
|
|
7943
|
+
const meta = {
|
|
7944
|
+
url: context.url,
|
|
7945
|
+
semantic: context.semantic,
|
|
7946
|
+
transport: context.transport,
|
|
7947
|
+
location: context.location,
|
|
7948
|
+
size: buffer.length,
|
|
7949
|
+
encoding: "utf-8",
|
|
7950
|
+
mimeType: "text/plain",
|
|
7951
|
+
resolvedAt: context.timestamp.toISOString()
|
|
7952
|
+
};
|
|
7953
|
+
return {
|
|
7954
|
+
type: "text",
|
|
7955
|
+
content: text,
|
|
7956
|
+
meta
|
|
7957
|
+
};
|
|
7958
|
+
}
|
|
7959
|
+
async deposit(transport, location, data, _context) {
|
|
7960
|
+
if (!transport.write) {
|
|
7961
|
+
throw new SemanticError(`Transport "${transport.name}" does not support write operation`, this.name);
|
|
7962
|
+
}
|
|
7963
|
+
const buffer = Buffer.from(data, "utf-8");
|
|
7964
|
+
await transport.write(location, buffer);
|
|
7965
|
+
}
|
|
7966
|
+
async exists(transport, location, _context) {
|
|
7967
|
+
if (transport.exists) {
|
|
7968
|
+
return transport.exists(location);
|
|
7548
7969
|
}
|
|
7970
|
+
try {
|
|
7971
|
+
await transport.read(location);
|
|
7972
|
+
return true;
|
|
7973
|
+
} catch {
|
|
7974
|
+
return false;
|
|
7975
|
+
}
|
|
7976
|
+
}
|
|
7977
|
+
async delete(transport, location, _context) {
|
|
7978
|
+
if (!transport.delete) {
|
|
7979
|
+
throw new SemanticError(`Transport "${transport.name}" does not support delete operation`, this.name);
|
|
7980
|
+
}
|
|
7981
|
+
await transport.delete(location);
|
|
7982
|
+
}
|
|
7983
|
+
}
|
|
7984
|
+
var textHandler = new TextSemanticHandler;
|
|
7985
|
+
function toBuffer(data) {
|
|
7986
|
+
if (Buffer.isBuffer(data)) {
|
|
7987
|
+
return data;
|
|
7988
|
+
}
|
|
7989
|
+
if (data instanceof Uint8Array) {
|
|
7990
|
+
return Buffer.from(data);
|
|
7991
|
+
}
|
|
7992
|
+
if (data instanceof ArrayBuffer) {
|
|
7993
|
+
return Buffer.from(data);
|
|
7994
|
+
}
|
|
7995
|
+
if (Array.isArray(data)) {
|
|
7996
|
+
return Buffer.from(data);
|
|
7997
|
+
}
|
|
7998
|
+
throw new SemanticError(`Unsupported binary input type`, "binary");
|
|
7999
|
+
}
|
|
8000
|
+
|
|
8001
|
+
class BinarySemanticHandler {
|
|
8002
|
+
name = "binary";
|
|
8003
|
+
async resolve(transport, location, context) {
|
|
8004
|
+
const buffer = await transport.read(location);
|
|
8005
|
+
const meta = {
|
|
8006
|
+
url: context.url,
|
|
8007
|
+
semantic: context.semantic,
|
|
8008
|
+
transport: context.transport,
|
|
8009
|
+
location: context.location,
|
|
8010
|
+
size: buffer.length,
|
|
8011
|
+
resolvedAt: context.timestamp.toISOString()
|
|
8012
|
+
};
|
|
8013
|
+
return {
|
|
8014
|
+
type: "binary",
|
|
8015
|
+
content: buffer,
|
|
8016
|
+
meta
|
|
8017
|
+
};
|
|
8018
|
+
}
|
|
8019
|
+
async deposit(transport, location, data, _context) {
|
|
8020
|
+
if (!transport.write) {
|
|
8021
|
+
throw new SemanticError(`Transport "${transport.name}" does not support write operation`, this.name);
|
|
8022
|
+
}
|
|
8023
|
+
const buffer = toBuffer(data);
|
|
8024
|
+
await transport.write(location, buffer);
|
|
8025
|
+
}
|
|
8026
|
+
async exists(transport, location, _context) {
|
|
8027
|
+
if (transport.exists) {
|
|
8028
|
+
return transport.exists(location);
|
|
8029
|
+
}
|
|
8030
|
+
try {
|
|
8031
|
+
await transport.read(location);
|
|
8032
|
+
return true;
|
|
8033
|
+
} catch {
|
|
8034
|
+
return false;
|
|
8035
|
+
}
|
|
8036
|
+
}
|
|
8037
|
+
async delete(transport, location, _context) {
|
|
8038
|
+
if (!transport.delete) {
|
|
8039
|
+
throw new SemanticError(`Transport "${transport.name}" does not support delete operation`, this.name);
|
|
8040
|
+
}
|
|
8041
|
+
await transport.delete(location);
|
|
8042
|
+
}
|
|
8043
|
+
}
|
|
8044
|
+
var binaryHandler = new BinarySemanticHandler;
|
|
8045
|
+
var handlers2 = new Map([
|
|
8046
|
+
["text", textHandler],
|
|
8047
|
+
["binary", binaryHandler]
|
|
8048
|
+
]);
|
|
8049
|
+
class MemoryStateStore {
|
|
8050
|
+
logs = new Map;
|
|
8051
|
+
blobs = new Map;
|
|
8052
|
+
async saveLog(key, data) {
|
|
8053
|
+
this.logs.set(key, data);
|
|
8054
|
+
}
|
|
8055
|
+
async loadLog(key) {
|
|
8056
|
+
return this.logs.get(key) ?? null;
|
|
8057
|
+
}
|
|
8058
|
+
async deleteLog(key) {
|
|
8059
|
+
this.logs.delete(key);
|
|
8060
|
+
}
|
|
8061
|
+
async listLogs() {
|
|
8062
|
+
return [...this.logs.keys()];
|
|
7549
8063
|
}
|
|
8064
|
+
async saveBlob(ref, data) {
|
|
8065
|
+
this.blobs.set(ref, data);
|
|
8066
|
+
}
|
|
8067
|
+
async loadBlob(ref) {
|
|
8068
|
+
return this.blobs.get(ref) ?? null;
|
|
8069
|
+
}
|
|
8070
|
+
async deleteBlob(ref) {
|
|
8071
|
+
this.blobs.delete(ref);
|
|
8072
|
+
}
|
|
8073
|
+
}
|
|
8074
|
+
function generateRef(data) {
|
|
8075
|
+
const hash = createHash("sha256").update(data).digest("hex");
|
|
8076
|
+
return `sha256-${hash}`;
|
|
8077
|
+
}
|
|
8078
|
+
|
|
8079
|
+
class StateAssetsImpl {
|
|
8080
|
+
sandbox;
|
|
8081
|
+
store;
|
|
8082
|
+
uploadedPaths = new Set;
|
|
8083
|
+
constructor(options) {
|
|
8084
|
+
this.sandbox = options.sandbox;
|
|
8085
|
+
this.store = options.store;
|
|
8086
|
+
}
|
|
8087
|
+
async uploadBuffer(data, remotePath) {
|
|
8088
|
+
const ref = generateRef(data);
|
|
8089
|
+
await this.sandbox.upload(data, remotePath);
|
|
8090
|
+
await this.store.saveBlob(ref, data);
|
|
8091
|
+
this.uploadedPaths.add(remotePath);
|
|
8092
|
+
return ref;
|
|
8093
|
+
}
|
|
8094
|
+
async downloadBuffer(remotePath, options) {
|
|
8095
|
+
const data = await this.sandbox.download(remotePath);
|
|
8096
|
+
if (options?.persist) {
|
|
8097
|
+
const ref = generateRef(data);
|
|
8098
|
+
await this.store.saveBlob(ref, data);
|
|
8099
|
+
return ref;
|
|
8100
|
+
}
|
|
8101
|
+
return data;
|
|
8102
|
+
}
|
|
8103
|
+
list() {
|
|
8104
|
+
return [...this.uploadedPaths];
|
|
8105
|
+
}
|
|
8106
|
+
}
|
|
8107
|
+
// src/mixins/withState.ts
|
|
8108
|
+
function withState(Base) {
|
|
8109
|
+
return class extends Base {
|
|
8110
|
+
fs;
|
|
8111
|
+
env;
|
|
8112
|
+
storage;
|
|
8113
|
+
stateLog;
|
|
8114
|
+
constructor(config) {
|
|
8115
|
+
super(config);
|
|
8116
|
+
const stateConfig = config.state;
|
|
8117
|
+
const state = createState({
|
|
8118
|
+
sandbox: this,
|
|
8119
|
+
env: stateConfig?.env,
|
|
8120
|
+
enableRecord: stateConfig?.enableRecord
|
|
8121
|
+
});
|
|
8122
|
+
this.fs = state.fs;
|
|
8123
|
+
this.env = state.env;
|
|
8124
|
+
this.storage = state.storage;
|
|
8125
|
+
this.stateLog = state.stateLog;
|
|
8126
|
+
if (stateConfig?.initializeLog) {
|
|
8127
|
+
replayStateLog(stateConfig.initializeLog, this);
|
|
8128
|
+
}
|
|
8129
|
+
}
|
|
8130
|
+
getStateLog() {
|
|
8131
|
+
return this.stateLog;
|
|
8132
|
+
}
|
|
8133
|
+
};
|
|
8134
|
+
}
|
|
8135
|
+
// src/mixins/withNodeExecute.ts
|
|
8136
|
+
function withNodeExecute(Base) {
|
|
8137
|
+
return class extends Base {
|
|
8138
|
+
nodeChecked = false;
|
|
8139
|
+
constructor(config) {
|
|
8140
|
+
super(config);
|
|
8141
|
+
}
|
|
8142
|
+
async execute(code) {
|
|
8143
|
+
if (!this.nodeChecked) {
|
|
8144
|
+
const check = await this.shell("which node");
|
|
8145
|
+
if (!check.success) {
|
|
8146
|
+
throw new ExecutionError("Node.js is not installed. Please install Node.js or use a different isolator (cloudflare/e2b).");
|
|
8147
|
+
}
|
|
8148
|
+
this.nodeChecked = true;
|
|
8149
|
+
}
|
|
8150
|
+
const escapedCode = code.replace(/'/g, "'\\''");
|
|
8151
|
+
const result = await this.shell(`node -e '${escapedCode}'`);
|
|
8152
|
+
return {
|
|
8153
|
+
success: result.success,
|
|
8154
|
+
stdout: result.stdout,
|
|
8155
|
+
stderr: result.stderr,
|
|
8156
|
+
exitCode: result.exitCode,
|
|
8157
|
+
executionTime: result.executionTime
|
|
8158
|
+
};
|
|
8159
|
+
}
|
|
8160
|
+
};
|
|
8161
|
+
}
|
|
8162
|
+
// src/mixins/withPythonExecute.ts
|
|
8163
|
+
function withPythonExecute(Base) {
|
|
8164
|
+
return class extends Base {
|
|
8165
|
+
pythonChecked = false;
|
|
8166
|
+
constructor(config) {
|
|
8167
|
+
super(config);
|
|
8168
|
+
}
|
|
8169
|
+
async execute(code) {
|
|
8170
|
+
if (!this.pythonChecked) {
|
|
8171
|
+
const check = await this.shell("which python3");
|
|
8172
|
+
if (!check.success) {
|
|
8173
|
+
throw new ExecutionError("Python 3 is not installed. Please install Python 3 or use a different isolator (cloudflare/e2b).");
|
|
8174
|
+
}
|
|
8175
|
+
this.pythonChecked = true;
|
|
8176
|
+
}
|
|
8177
|
+
const escapedCode = code.replace(/'/g, "'\\''");
|
|
8178
|
+
const result = await this.shell(`python3 -c '${escapedCode}'`);
|
|
8179
|
+
return {
|
|
8180
|
+
success: result.success,
|
|
8181
|
+
stdout: result.stdout,
|
|
8182
|
+
stderr: result.stderr,
|
|
8183
|
+
exitCode: result.exitCode,
|
|
8184
|
+
executionTime: result.executionTime
|
|
8185
|
+
};
|
|
8186
|
+
}
|
|
8187
|
+
};
|
|
7550
8188
|
}
|
|
7551
8189
|
export {
|
|
8190
|
+
withState,
|
|
8191
|
+
withPythonExecute,
|
|
8192
|
+
withNodeExecute,
|
|
8193
|
+
loadStateLog,
|
|
8194
|
+
buildStateLog,
|
|
7552
8195
|
TimeoutError,
|
|
8196
|
+
StateStorage,
|
|
8197
|
+
StateFS,
|
|
8198
|
+
StateError,
|
|
8199
|
+
StateEnv,
|
|
7553
8200
|
SandboxError,
|
|
7554
|
-
Sandbox,
|
|
7555
|
-
Runtime,
|
|
7556
8201
|
LocalIsolator,
|
|
7557
8202
|
Isolator,
|
|
7558
8203
|
IsolationError,
|
|
7559
|
-
|
|
7560
|
-
FileSystemError,
|
|
8204
|
+
FileSystemError2 as FileSystemError,
|
|
7561
8205
|
ExecutionError,
|
|
7562
|
-
CloudflareContainerIsolator
|
|
8206
|
+
CloudflareContainerIsolator,
|
|
8207
|
+
BaseSandbox
|
|
7563
8208
|
};
|
|
7564
8209
|
|
|
7565
|
-
//# debugId=
|
|
8210
|
+
//# debugId=7693E135F99AC4E664756E2164756E21
|