@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.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
- runtime;
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 execute(options) {
7244
- const { code, env = {}, timeout = 30000 } = options;
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 command = this.buildCommand(code);
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: true,
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 || 0,
7262
- metadata: {
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
- if (error.exitCode !== undefined) {
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
- buildCommand(code) {
7287
- switch (this.runtime) {
7288
- case "node":
7289
- return ["node", "--eval", code];
7290
- case "python":
7291
- return ["python3", "-c", code];
7292
- case "bash":
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
- getFileSystem() {
7299
- return {
7300
- write: async (filePath, data) => {
7301
- try {
7302
- const fullPath = path6.join(this.workDir, filePath);
7303
- await fs.mkdir(path6.dirname(fullPath), { recursive: true });
7304
- await fs.writeFile(fullPath, data, "utf-8");
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 (error) {
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
- runtime;
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 execute(options) {
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: options.code,
7422
- runtime: this.runtime,
7423
- env: options.env || {},
7424
- timeout: options.timeout || 30000
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 result;
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(`Execution failed: ${error.message}`);
7379
+ throw new ExecutionError(`Shell execution failed: ${error.message}`);
7435
7380
  }
7436
7381
  }
7437
- getFileSystem() {
7438
- return {
7439
- write: async () => {
7440
- throw new FileSystemError("Filesystem not yet implemented for CloudflareContainerIsolator");
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 Sandbox {
7399
+ class BaseSandbox {
7486
7400
  isolator;
7487
- runtime;
7488
- eventHandlers = new Map;
7489
- fs;
7401
+ config;
7490
7402
  constructor(config) {
7491
- this.isolator = this.createIsolator(config.isolator, config.runtime);
7492
- this.fs = this.isolator.getFileSystem();
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, runtime) {
7406
+ createIsolator(isolatorType) {
7496
7407
  switch (isolatorType) {
7497
7408
  case "local":
7498
- return new LocalIsolator(runtime);
7409
+ return new LocalIsolator;
7499
7410
  case "cloudflare":
7500
- return new CloudflareContainerIsolator(runtime);
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
- createRuntime(_runtimeType, isolator) {
7510
- return new GenericRuntime(isolator);
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
- async execute(options) {
7513
- this.emit("execute:start", options);
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 result = await this.runtime.execute(options);
7516
- this.emit("execute:success", result);
7517
- return result;
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
- this.emit("execute:error", error);
7520
- throw error;
7521
- } finally {
7522
- this.emit("execute:complete");
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
- async writeFile(filePath, data) {
7526
- return this.fs.write(filePath, data);
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 readFile(filePath) {
7529
- return this.fs.read(filePath);
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 destroy() {
7532
- await this.runtime.cleanup();
7533
- await this.isolator.destroy();
7534
- this.eventHandlers.clear();
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
- on(event, handler) {
7537
- if (!this.eventHandlers.has(event)) {
7538
- this.eventHandlers.set(event, []);
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
- emit(event, ...args) {
7543
- const handlers = this.eventHandlers.get(event);
7544
- if (handlers) {
7545
- for (const handler of handlers) {
7546
- handler(...args);
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
- GenericRuntime,
7560
- FileSystemError,
8204
+ FileSystemError2 as FileSystemError,
7561
8205
  ExecutionError,
7562
- CloudflareContainerIsolator
8206
+ CloudflareContainerIsolator,
8207
+ BaseSandbox
7563
8208
  };
7564
8209
 
7565
- //# debugId=09D6DD78D2CFDED564756E2164756E21
8210
+ //# debugId=7693E135F99AC4E664756E2164756E21