@cloudflare/sandbox 0.6.11 → 0.7.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.
@@ -10,6 +10,45 @@ function getEnvString(env, key) {
10
10
  const value = env?.[key];
11
11
  return typeof value === "string" ? value : void 0;
12
12
  }
13
+ /**
14
+ * Filter environment variables object to only include string values.
15
+ * Skips undefined, null, and non-string values.
16
+ *
17
+ * Use this when you only need the defined values (e.g., for per-command env
18
+ * where undefined means "don't override").
19
+ *
20
+ * @param envVars - Object that may contain undefined values
21
+ * @returns Clean object with only string values
22
+ */
23
+ function filterEnvVars(envVars) {
24
+ const filtered = {};
25
+ for (const [key, value] of Object.entries(envVars)) if (value != null && typeof value === "string") filtered[key] = value;
26
+ return filtered;
27
+ }
28
+ /**
29
+ * Partition environment variables into values to set and keys to unset.
30
+ *
31
+ * - String values → toSet (will be exported)
32
+ * - undefined/null → toUnset (will be unset)
33
+ *
34
+ * This enables idiomatic JS patterns where undefined means "remove":
35
+ * ```typescript
36
+ * await sandbox.setEnvVars({
37
+ * API_KEY: 'new-key', // will be set
38
+ * OLD_VAR: undefined, // will be unset
39
+ * });
40
+ * ```
41
+ */
42
+ function partitionEnvVars(envVars) {
43
+ const toSet = {};
44
+ const toUnset = [];
45
+ for (const [key, value] of Object.entries(envVars)) if (value != null && typeof value === "string") toSet[key] = value;
46
+ else toUnset.push(key);
47
+ return {
48
+ toSet,
49
+ toUnset
50
+ };
51
+ }
13
52
 
14
53
  //#endregion
15
54
  //#region ../shared/dist/git.js
@@ -670,5 +709,5 @@ function generateRequestId() {
670
709
  }
671
710
 
672
711
  //#endregion
673
- export { isExecResult as a, shellEscape as c, TraceContext as d, Execution as f, getEnvString as g, extractRepoName as h, isWSStreamChunk as i, createLogger as l, GitLogger as m, isWSError as n, isProcess as o, ResultImpl as p, isWSResponse as r, isProcessStatus as s, generateRequestId as t, createNoOpLogger as u };
674
- //# sourceMappingURL=dist-c_xYW5i_.js.map
712
+ export { getEnvString as _, isExecResult as a, shellEscape as c, TraceContext as d, Execution as f, filterEnvVars as g, extractRepoName as h, isWSStreamChunk as i, createLogger as l, GitLogger as m, isWSError as n, isProcess as o, ResultImpl as p, isWSResponse as r, isProcessStatus as s, generateRequestId as t, createNoOpLogger as u, partitionEnvVars as v };
713
+ //# sourceMappingURL=dist-BpbdH8ry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dist-BpbdH8ry.js","names":["LogLevelEnum","LogLevelEnum"],"sources":["../../shared/dist/env.js","../../shared/dist/git.js","../../shared/dist/interpreter-types.js","../../shared/dist/logger/types.js","../../shared/dist/logger/logger.js","../../shared/dist/logger/trace-context.js","../../shared/dist/logger/index.js","../../shared/dist/shell-escape.js","../../shared/dist/types.js","../../shared/dist/ws-types.js"],"sourcesContent":["/**\n * Safely extract a string value from an environment object\n *\n * @param env - Environment object with dynamic keys\n * @param key - The environment variable key to access\n * @returns The string value if present and is a string, undefined otherwise\n */\nexport function getEnvString(env, key) {\n const value = env?.[key];\n return typeof value === 'string' ? value : undefined;\n}\n/**\n * Filter environment variables object to only include string values.\n * Skips undefined, null, and non-string values.\n *\n * Use this when you only need the defined values (e.g., for per-command env\n * where undefined means \"don't override\").\n *\n * @param envVars - Object that may contain undefined values\n * @returns Clean object with only string values\n */\nexport function filterEnvVars(envVars) {\n const filtered = {};\n for (const [key, value] of Object.entries(envVars)) {\n if (value != null && typeof value === 'string') {\n filtered[key] = value;\n }\n }\n return filtered;\n}\n/**\n * Partition environment variables into values to set and keys to unset.\n *\n * - String values → toSet (will be exported)\n * - undefined/null → toUnset (will be unset)\n *\n * This enables idiomatic JS patterns where undefined means \"remove\":\n * ```typescript\n * await sandbox.setEnvVars({\n * API_KEY: 'new-key', // will be set\n * OLD_VAR: undefined, // will be unset\n * });\n * ```\n */\nexport function partitionEnvVars(envVars) {\n const toSet = {};\n const toUnset = [];\n for (const [key, value] of Object.entries(envVars)) {\n if (value != null && typeof value === 'string') {\n toSet[key] = value;\n }\n else {\n toUnset.push(key);\n }\n }\n return { toSet, toUnset };\n}\n","/**\n * Fallback repository name used when URL parsing fails\n */\nexport const FALLBACK_REPO_NAME = 'repository';\n/**\n * Extract repository name from a Git URL\n *\n * Supports multiple URL formats:\n * - HTTPS: https://github.com/user/repo.git → repo\n * - HTTPS without .git: https://github.com/user/repo → repo\n * - SSH: git@github.com:user/repo.git → repo\n * - GitLab/others: https://gitlab.com/org/project.git → project\n *\n * @param repoUrl - Git repository URL (HTTPS or SSH format)\n * @returns Repository name extracted from URL, or 'repository' as fallback\n */\nexport function extractRepoName(repoUrl) {\n // Try parsing as standard URL (https://, http://)\n try {\n const url = new URL(repoUrl);\n const pathParts = url.pathname.split('/');\n const lastPart = pathParts[pathParts.length - 1];\n if (lastPart) {\n return lastPart.replace(/\\.git$/, '');\n }\n }\n catch {\n // Not a standard URL, try SSH format\n }\n // For SSH URLs (git@github.com:user/repo.git), split by : and / to get last segment\n // Only process if the URL contains path delimiters\n if (repoUrl.includes(':') || repoUrl.includes('/')) {\n const segments = repoUrl.split(/[:/]/).filter(Boolean);\n const lastSegment = segments[segments.length - 1];\n if (lastSegment) {\n return lastSegment.replace(/\\.git$/, '');\n }\n }\n return FALLBACK_REPO_NAME;\n}\n/**\n * Redact credentials from URLs for secure logging\n *\n * Replaces any credentials (username:password, tokens, etc.) embedded\n * in URLs with ****** to prevent sensitive data exposure in logs.\n * Works with URLs embedded in text (e.g., \"Error: https://token@github.com/repo.git failed\")\n *\n * @param text - String that may contain URLs with credentials\n * @returns String with credentials redacted from any URLs\n */\nexport function redactCredentials(text) {\n // Scan for http(s):// URLs and redact any credentials found\n let result = text;\n let pos = 0;\n while (pos < result.length) {\n const httpPos = result.indexOf('http://', pos);\n const httpsPos = result.indexOf('https://', pos);\n let protocolPos = -1;\n let protocolLen = 0;\n if (httpPos === -1 && httpsPos === -1)\n break;\n if (httpPos !== -1 && (httpsPos === -1 || httpPos < httpsPos)) {\n protocolPos = httpPos;\n protocolLen = 7; // 'http://'.length\n }\n else {\n protocolPos = httpsPos;\n protocolLen = 8; // 'https://'.length\n }\n // Look for @ after the protocol\n const searchStart = protocolPos + protocolLen;\n const atPos = result.indexOf('@', searchStart);\n // Find where the URL ends (whitespace, quotes, or structural delimiters)\n let urlEnd = searchStart;\n while (urlEnd < result.length) {\n const char = result[urlEnd];\n if (/[\\s\"'`<>,;{}[\\]]/.test(char))\n break;\n urlEnd++;\n }\n if (atPos !== -1 && atPos < urlEnd) {\n result = `${result.substring(0, searchStart)}******${result.substring(atPos)}`;\n pos = searchStart + 6; // Move past '******'\n }\n else {\n pos = protocolPos + protocolLen;\n }\n }\n return result;\n}\n/**\n * Sanitize data by redacting credentials from any strings\n * Recursively processes objects and arrays to ensure credentials are never leaked\n */\nexport function sanitizeGitData(data) {\n // Handle primitives\n if (typeof data === 'string') {\n return redactCredentials(data);\n }\n if (data === null || data === undefined) {\n return data;\n }\n // Handle arrays\n if (Array.isArray(data)) {\n return data.map((item) => sanitizeGitData(item));\n }\n // Handle objects - recursively sanitize all fields\n if (typeof data === 'object') {\n const result = {};\n for (const [key, value] of Object.entries(data)) {\n result[key] = sanitizeGitData(value);\n }\n return result;\n }\n return data;\n}\n/**\n * Logger wrapper that automatically sanitizes git credentials\n */\nexport class GitLogger {\n baseLogger;\n constructor(baseLogger) {\n this.baseLogger = baseLogger;\n }\n sanitizeContext(context) {\n return context\n ? sanitizeGitData(context)\n : context;\n }\n sanitizeError(error) {\n if (!error)\n return error;\n // Create a new error with sanitized message and stack\n const sanitized = new Error(redactCredentials(error.message));\n sanitized.name = error.name;\n if (error.stack) {\n sanitized.stack = redactCredentials(error.stack);\n }\n // Preserve other enumerable properties\n const sanitizedRecord = sanitized;\n const errorRecord = error;\n for (const key of Object.keys(error)) {\n if (key !== 'message' && key !== 'stack' && key !== 'name') {\n sanitizedRecord[key] = sanitizeGitData(errorRecord[key]);\n }\n }\n return sanitized;\n }\n debug(message, context) {\n this.baseLogger.debug(message, this.sanitizeContext(context));\n }\n info(message, context) {\n this.baseLogger.info(message, this.sanitizeContext(context));\n }\n warn(message, context) {\n this.baseLogger.warn(message, this.sanitizeContext(context));\n }\n error(message, error, context) {\n this.baseLogger.error(message, this.sanitizeError(error), this.sanitizeContext(context));\n }\n child(context) {\n const sanitized = sanitizeGitData(context);\n const childLogger = this.baseLogger.child(sanitized);\n return new GitLogger(childLogger);\n }\n}\n","// Execution Result Container\nexport class Execution {\n code;\n context;\n /**\n * All results from the execution\n */\n results = [];\n /**\n * Accumulated stdout and stderr\n */\n logs = {\n stdout: [],\n stderr: []\n };\n /**\n * Execution error if any\n */\n error;\n /**\n * Execution count (for interpreter)\n */\n executionCount;\n constructor(code, context) {\n this.code = code;\n this.context = context;\n }\n /**\n * Convert to a plain object for serialization\n */\n toJSON() {\n return {\n code: this.code,\n logs: this.logs,\n error: this.error,\n executionCount: this.executionCount,\n results: this.results.map((result) => ({\n text: result.text,\n html: result.html,\n png: result.png,\n jpeg: result.jpeg,\n svg: result.svg,\n latex: result.latex,\n markdown: result.markdown,\n javascript: result.javascript,\n json: result.json,\n chart: result.chart,\n data: result.data\n }))\n };\n }\n}\n// Implementation of Result\nexport class ResultImpl {\n raw;\n constructor(raw) {\n this.raw = raw;\n }\n get text() {\n return this.raw.text || this.raw.data?.['text/plain'];\n }\n get html() {\n return this.raw.html || this.raw.data?.['text/html'];\n }\n get png() {\n return this.raw.png || this.raw.data?.['image/png'];\n }\n get jpeg() {\n return this.raw.jpeg || this.raw.data?.['image/jpeg'];\n }\n get svg() {\n return this.raw.svg || this.raw.data?.['image/svg+xml'];\n }\n get latex() {\n return this.raw.latex || this.raw.data?.['text/latex'];\n }\n get markdown() {\n return this.raw.markdown || this.raw.data?.['text/markdown'];\n }\n get javascript() {\n return this.raw.javascript || this.raw.data?.['application/javascript'];\n }\n get json() {\n return this.raw.json || this.raw.data?.['application/json'];\n }\n get chart() {\n return this.raw.chart;\n }\n get data() {\n return this.raw.data;\n }\n formats() {\n const formats = [];\n if (this.text)\n formats.push('text');\n if (this.html)\n formats.push('html');\n if (this.png)\n formats.push('png');\n if (this.jpeg)\n formats.push('jpeg');\n if (this.svg)\n formats.push('svg');\n if (this.latex)\n formats.push('latex');\n if (this.markdown)\n formats.push('markdown');\n if (this.javascript)\n formats.push('javascript');\n if (this.json)\n formats.push('json');\n if (this.chart)\n formats.push('chart');\n return formats;\n }\n}\n","/**\n * Logger types for Cloudflare Sandbox SDK\n *\n * Provides structured, trace-aware logging across Worker, Durable Object, and Container.\n */\n/**\n * Log levels (from most to least verbose)\n */\nexport var LogLevel;\n(function (LogLevel) {\n LogLevel[LogLevel[\"DEBUG\"] = 0] = \"DEBUG\";\n LogLevel[LogLevel[\"INFO\"] = 1] = \"INFO\";\n LogLevel[LogLevel[\"WARN\"] = 2] = \"WARN\";\n LogLevel[LogLevel[\"ERROR\"] = 3] = \"ERROR\";\n})(LogLevel || (LogLevel = {}));\n","/**\n * Logger implementation\n */\nimport { LogLevel as LogLevelEnum } from './types.js';\n/**\n * ANSI color codes for terminal output\n */\nconst COLORS = {\n reset: '\\x1b[0m',\n debug: '\\x1b[36m', // Cyan\n info: '\\x1b[32m', // Green\n warn: '\\x1b[33m', // Yellow\n error: '\\x1b[31m', // Red\n dim: '\\x1b[2m' // Dim\n};\n/**\n * CloudflareLogger implements structured logging with support for\n * both JSON output (production) and pretty printing (development).\n */\nexport class CloudflareLogger {\n baseContext;\n minLevel;\n pretty;\n /**\n * Create a new CloudflareLogger\n *\n * @param baseContext Base context included in all log entries\n * @param minLevel Minimum log level to output (default: INFO)\n * @param pretty Enable pretty printing for human-readable output (default: false)\n */\n constructor(baseContext, minLevel = LogLevelEnum.INFO, pretty = false) {\n this.baseContext = baseContext;\n this.minLevel = minLevel;\n this.pretty = pretty;\n }\n /**\n * Log debug-level message\n */\n debug(message, context) {\n if (this.shouldLog(LogLevelEnum.DEBUG)) {\n const logData = this.buildLogData('debug', message, context);\n this.output(console.log, logData);\n }\n }\n /**\n * Log info-level message\n */\n info(message, context) {\n if (this.shouldLog(LogLevelEnum.INFO)) {\n const logData = this.buildLogData('info', message, context);\n this.output(console.log, logData);\n }\n }\n /**\n * Log warning-level message\n */\n warn(message, context) {\n if (this.shouldLog(LogLevelEnum.WARN)) {\n const logData = this.buildLogData('warn', message, context);\n this.output(console.warn, logData);\n }\n }\n /**\n * Log error-level message\n */\n error(message, error, context) {\n if (this.shouldLog(LogLevelEnum.ERROR)) {\n const logData = this.buildLogData('error', message, context, error);\n this.output(console.error, logData);\n }\n }\n /**\n * Create a child logger with additional context\n */\n child(context) {\n return new CloudflareLogger({ ...this.baseContext, ...context }, this.minLevel, this.pretty);\n }\n /**\n * Check if a log level should be output\n */\n shouldLog(level) {\n return level >= this.minLevel;\n }\n /**\n * Build log data object\n */\n buildLogData(level, message, context, error) {\n const logData = {\n level,\n msg: message,\n ...this.baseContext,\n ...context,\n timestamp: new Date().toISOString()\n };\n // Add error details if provided\n if (error) {\n logData.error = {\n message: error.message,\n stack: error.stack,\n name: error.name\n };\n }\n return logData;\n }\n /**\n * Output log data to console (pretty or JSON)\n */\n output(consoleFn, data) {\n if (this.pretty) {\n this.outputPretty(consoleFn, data);\n }\n else {\n this.outputJson(consoleFn, data);\n }\n }\n /**\n * Output as JSON (production)\n */\n outputJson(consoleFn, data) {\n consoleFn(JSON.stringify(data));\n }\n /**\n * Output as pretty-printed, colored text (development)\n *\n * Format: LEVEL [component] message (trace: tr_...) {context}\n * Example: INFO [sandbox-do] Command started (trace: tr_7f3a9b2c) {commandId: \"cmd-123\"}\n */\n outputPretty(consoleFn, data) {\n const { level, msg, timestamp, traceId, component, sandboxId, sessionId, processId, commandId, operation, duration, error, ...rest } = data;\n // Build the main log line\n const levelStr = String(level || 'INFO').toUpperCase();\n const levelColor = this.getLevelColor(levelStr);\n const componentBadge = component ? `[${component}]` : '';\n const traceIdShort = traceId ? String(traceId).substring(0, 12) : '';\n // Start with level and component\n let logLine = `${levelColor}${levelStr.padEnd(5)}${COLORS.reset} ${componentBadge} ${msg}`;\n // Add trace ID if present\n if (traceIdShort) {\n logLine += ` ${COLORS.dim}(trace: ${traceIdShort})${COLORS.reset}`;\n }\n // Collect important context fields\n const contextFields = [];\n if (operation)\n contextFields.push(`operation: ${operation}`);\n if (commandId)\n contextFields.push(`commandId: ${String(commandId).substring(0, 12)}`);\n if (sandboxId)\n contextFields.push(`sandboxId: ${sandboxId}`);\n if (sessionId)\n contextFields.push(`sessionId: ${String(sessionId).substring(0, 12)}`);\n if (processId)\n contextFields.push(`processId: ${processId}`);\n if (duration !== undefined)\n contextFields.push(`duration: ${duration}ms`);\n // Add important context inline\n if (contextFields.length > 0) {\n logLine += ` ${COLORS.dim}{${contextFields.join(', ')}}${COLORS.reset}`;\n }\n // Output main log line\n consoleFn(logLine);\n // Output error details on separate lines if present\n if (error && typeof error === 'object') {\n const errorObj = error;\n if (errorObj.message) {\n consoleFn(` ${COLORS.error}Error: ${errorObj.message}${COLORS.reset}`);\n }\n if (errorObj.stack) {\n consoleFn(` ${COLORS.dim}${errorObj.stack}${COLORS.reset}`);\n }\n }\n // Output additional context if present\n if (Object.keys(rest).length > 0) {\n consoleFn(` ${COLORS.dim}${JSON.stringify(rest, null, 2)}${COLORS.reset}`);\n }\n }\n /**\n * Get ANSI color code for log level\n */\n getLevelColor(level) {\n const levelLower = level.toLowerCase();\n switch (levelLower) {\n case 'debug':\n return COLORS.debug;\n case 'info':\n return COLORS.info;\n case 'warn':\n return COLORS.warn;\n case 'error':\n return COLORS.error;\n default:\n return COLORS.reset;\n }\n }\n}\n","/**\n * Trace context utilities for request correlation\n *\n * Trace IDs enable correlating logs across distributed components:\n * Worker → Durable Object → Container → back\n *\n * The trace ID is propagated via the X-Trace-Id HTTP header.\n */\n/**\n * Utility for managing trace context across distributed components\n */\n// biome-ignore lint/complexity/noStaticOnlyClass: Keep as class for namespace grouping and discoverability\nexport class TraceContext {\n /**\n * HTTP header name for trace ID propagation\n */\n static TRACE_HEADER = 'X-Trace-Id';\n /**\n * Generate a new trace ID\n *\n * Format: \"tr_\" + 16 random hex characters\n * Example: \"tr_7f3a9b2c4e5d6f1a\"\n *\n * @returns Newly generated trace ID\n */\n static generate() {\n // Use crypto.randomUUID() for randomness, extract 16 hex chars\n const randomHex = crypto.randomUUID().replace(/-/g, '').substring(0, 16);\n return `tr_${randomHex}`;\n }\n /**\n * Extract trace ID from HTTP request headers\n *\n * @param headers Request headers\n * @returns Trace ID if present, null otherwise\n */\n static fromHeaders(headers) {\n return headers.get(TraceContext.TRACE_HEADER);\n }\n /**\n * Create headers object with trace ID for outgoing requests\n *\n * @param traceId Trace ID to include\n * @returns Headers object with X-Trace-Id set\n */\n static toHeaders(traceId) {\n return { [TraceContext.TRACE_HEADER]: traceId };\n }\n /**\n * Get the header name used for trace ID propagation\n *\n * @returns Header name (\"X-Trace-Id\")\n */\n static getHeaderName() {\n return TraceContext.TRACE_HEADER;\n }\n}\n","/**\n * Logger module\n *\n * Provides structured, trace-aware logging with:\n * - Explicit logger passing via constructor injection\n * - Pretty printing for local development\n * - JSON output for production\n * - Environment auto-detection\n * - Log level configuration\n *\n * Usage:\n *\n * ```typescript\n * // Create a logger at entry point\n * const logger = createLogger({ component: 'sandbox-do', traceId: 'tr_abc123' });\n *\n * // Pass to classes via constructor\n * const service = new MyService(logger);\n *\n * // Create child loggers for additional context\n * const execLogger = logger.child({ operation: 'exec', commandId: 'cmd-456' });\n * execLogger.info('Operation started');\n * ```\n */\nimport { CloudflareLogger } from './logger.js';\nimport { TraceContext } from './trace-context.js';\nimport { LogLevel as LogLevelEnum } from './types.js';\nexport { CloudflareLogger } from './logger.js';\nexport { TraceContext } from './trace-context.js';\nexport { LogLevel as LogLevelEnum } from './types.js';\n/**\n * Create a no-op logger for testing\n *\n * Returns a logger that implements the Logger interface but does nothing.\n * Useful for tests that don't need actual logging output.\n *\n * @returns No-op logger instance\n *\n * @example\n * ```typescript\n * // In tests\n * const client = new HttpClient({\n * baseUrl: 'http://test.com',\n * logger: createNoOpLogger() // Optional - tests can enable real logging if needed\n * });\n * ```\n */\nexport function createNoOpLogger() {\n return {\n debug: () => { },\n info: () => { },\n warn: () => { },\n error: () => { },\n child: () => createNoOpLogger()\n };\n}\n/**\n * Create a new logger instance\n *\n * @param context Base context for the logger. Must include 'component'.\n * TraceId will be auto-generated if not provided.\n * @returns New logger instance\n *\n * @example\n * ```typescript\n * // In Durable Object\n * const logger = createLogger({\n * component: 'sandbox-do',\n * traceId: TraceContext.fromHeaders(request.headers) || TraceContext.generate(),\n * sandboxId: this.id\n * });\n *\n * // In Container\n * const logger = createLogger({\n * component: 'container',\n * traceId: TraceContext.fromHeaders(request.headers)!,\n * sessionId: this.id\n * });\n * ```\n */\nexport function createLogger(context) {\n const minLevel = getLogLevelFromEnv();\n const pretty = isPrettyPrintEnabled();\n const baseContext = {\n ...context,\n traceId: context.traceId || TraceContext.generate(),\n component: context.component\n };\n return new CloudflareLogger(baseContext, minLevel, pretty);\n}\n/**\n * Get log level from environment variable\n *\n * Checks SANDBOX_LOG_LEVEL env var, falls back to default based on environment.\n * Default: 'debug' for development, 'info' for production\n */\nfunction getLogLevelFromEnv() {\n const envLevel = getEnvVar('SANDBOX_LOG_LEVEL') || 'info';\n switch (envLevel.toLowerCase()) {\n case 'debug':\n return LogLevelEnum.DEBUG;\n case 'info':\n return LogLevelEnum.INFO;\n case 'warn':\n return LogLevelEnum.WARN;\n case 'error':\n return LogLevelEnum.ERROR;\n default:\n // Invalid level, fall back to info\n return LogLevelEnum.INFO;\n }\n}\n/**\n * Check if pretty printing should be enabled\n *\n * Checks SANDBOX_LOG_FORMAT env var, falls back to auto-detection:\n * - Local development: pretty (colored, human-readable)\n * - Production: json (structured)\n */\nfunction isPrettyPrintEnabled() {\n // Check explicit SANDBOX_LOG_FORMAT env var\n const format = getEnvVar('SANDBOX_LOG_FORMAT');\n if (format) {\n return format.toLowerCase() === 'pretty';\n }\n return false;\n}\n/**\n * Get environment variable value\n *\n * Supports both Node.js (process.env) and Bun (Bun.env)\n */\nfunction getEnvVar(name) {\n // Try process.env first (Node.js / Bun)\n if (typeof process !== 'undefined' && process.env) {\n return process.env[name];\n }\n // Try Bun.env (Bun runtime)\n if (typeof Bun !== 'undefined') {\n const bunEnv = Bun.env;\n if (bunEnv) {\n return bunEnv[name];\n }\n }\n return undefined;\n}\n","/**\n * Escapes a string for safe use in shell commands using POSIX single-quote escaping.\n * Prevents command injection by wrapping the string in single quotes and escaping\n * any single quotes within the string.\n */\nexport function shellEscape(str) {\n return `'${str.replace(/'/g, \"'\\\\''\")}'`;\n}\n","/**\n * Check if a process status indicates the process has terminated\n */\nexport function isTerminalStatus(status) {\n return (status === 'completed' ||\n status === 'failed' ||\n status === 'killed' ||\n status === 'error');\n}\n// Type guards for runtime validation\nexport function isExecResult(value) {\n return (value &&\n typeof value.success === 'boolean' &&\n typeof value.exitCode === 'number' &&\n typeof value.stdout === 'string' &&\n typeof value.stderr === 'string');\n}\nexport function isProcess(value) {\n return (value &&\n typeof value.id === 'string' &&\n typeof value.command === 'string' &&\n typeof value.status === 'string');\n}\nexport function isProcessStatus(value) {\n return [\n 'starting',\n 'running',\n 'completed',\n 'failed',\n 'killed',\n 'error'\n ].includes(value);\n}\n// Re-export interpreter types for convenience\nexport { Execution, ResultImpl } from './interpreter-types';\n","/**\n * WebSocket transport protocol types\n *\n * Enables multiplexing HTTP-like requests over a single WebSocket connection.\n * This reduces sub-request count when running inside Workers/Durable Objects.\n *\n * Protocol:\n * - Client sends WSRequest messages\n * - Server responds with WSResponse messages (matched by id)\n * - For streaming endpoints, server sends multiple WSStreamChunk messages\n * followed by a final WSResponse\n */\n/**\n * Type guard for WSRequest\n *\n * Note: Only validates the discriminator field (type === 'request').\n * Does not validate other required fields (id, method, path).\n * Use for routing messages; trust TypeScript for field validation.\n */\nexport function isWSRequest(msg) {\n return (typeof msg === 'object' &&\n msg !== null &&\n 'type' in msg &&\n msg.type === 'request');\n}\n/**\n * Type guard for WSResponse\n *\n * Note: Only validates the discriminator field (type === 'response').\n */\nexport function isWSResponse(msg) {\n return (typeof msg === 'object' &&\n msg !== null &&\n 'type' in msg &&\n msg.type === 'response');\n}\n/**\n * Type guard for WSStreamChunk\n *\n * Note: Only validates the discriminator field (type === 'stream').\n */\nexport function isWSStreamChunk(msg) {\n return (typeof msg === 'object' &&\n msg !== null &&\n 'type' in msg &&\n msg.type === 'stream');\n}\n/**\n * Type guard for WSError\n *\n * Note: Only validates the discriminator field (type === 'error').\n */\nexport function isWSError(msg) {\n return (typeof msg === 'object' &&\n msg !== null &&\n 'type' in msg &&\n msg.type === 'error');\n}\n/**\n * Generate a unique request ID\n */\nexport function generateRequestId() {\n return `ws_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as ProcessInfoResult, A as RequestConfig, B as FileChunk, C as WriteFileRequest, D as ContainerStub, E as BaseApiResponse, F as BucketProvider, G as ListFilesOptions, H as FileStreamEvent, I as ExecEvent, J as PortCloseResult, K as LogEvent, L as ExecOptions, M as SessionRequest, N as BaseExecOptions, O as ErrorResponse, P as BucketCredentials, Q as ProcessCleanupResult, R as ExecResult, S as ReadFileRequest, T as ExecuteResponse, U as GitCheckoutResult, V as FileMetadata, W as ISandbox, X as PortListResult, Y as PortExposeResult, Z as Process, _ as GitCheckoutRequest, _t as ExecutionResult, a as CreateSessionRequest, at as ProcessStatus, b as FileOperationRequest, c as DeleteSessionResponse, ct as StreamOptions, d as ProcessClient, dt as isExecResult, et as ProcessKillResult, f as ExposePortRequest, ft as isProcess, g as InterpreterClient, gt as Execution, h as ExecutionCallbacks, ht as CreateContextOptions, i as CommandsResponse, it as ProcessStartResult, j as ResponseHandler, k as HttpClientOptions, l as PingResponse, lt as WaitForLogResult, m as UnexposePortRequest, mt as CodeContext, n as getSandbox, nt as ProcessLogsResult, o as CreateSessionResponse, ot as SandboxOptions, p as PortClient, pt as isProcessStatus, q as MountBucketOptions, r as SandboxClient, rt as ProcessOptions, s as DeleteSessionRequest, st as SessionOptions, t as Sandbox, tt as ProcessListResult, u as UtilityClient, ut as WaitForPortOptions, v as GitClient, vt as RunCodeOptions, w as CommandClient, x as MkdirRequest, y as FileClient, z as ExecutionSession } from "./sandbox-HCG7Oeg0.js";
1
+ import { $ as ProcessKillResult, A as ResponseHandler, B as FileMetadata, C as CommandClient, D as ErrorResponse, E as ContainerStub, F as ExecEvent, G as LogEvent, H as GitCheckoutResult, I as ExecOptions, J as PortExposeResult, K as MountBucketOptions, L as ExecResult, M as BaseExecOptions, N as BucketCredentials, O as HttpClientOptions, P as BucketProvider, Q as ProcessInfoResult, R as ExecutionSession, S as WriteFileRequest, T as BaseApiResponse, U as ISandbox, V as FileStreamEvent, W as ListFilesOptions, X as Process, Y as PortListResult, Z as ProcessCleanupResult, _ as GitClient, _t as RunCodeOptions, a as CreateSessionRequest, at as SandboxOptions, b as MkdirRequest, c as DeleteSessionResponse, ct as WaitForLogResult, d as ProcessClient, dt as isProcess, et as ProcessListResult, f as PortClient, ft as isProcessStatus, g as GitCheckoutRequest, gt as ExecutionResult, h as InterpreterClient, ht as Execution, i as CommandsResponse, it as ProcessStatus, j as SessionRequest, k as RequestConfig, l as PingResponse, lt as WaitForPortOptions, m as ExecutionCallbacks, mt as CreateContextOptions, n as getSandbox, nt as ProcessOptions, o as CreateSessionResponse, ot as SessionOptions, p as UnexposePortRequest, pt as CodeContext, q as PortCloseResult, r as SandboxClient, rt as ProcessStartResult, s as DeleteSessionRequest, st as StreamOptions, t as Sandbox, tt as ProcessLogsResult, u as UtilityClient, ut as isExecResult, v as FileClient, w as ExecuteResponse, x as ReadFileRequest, y as FileOperationRequest, z as FileChunk } from "./sandbox-CEsJ1edi.js";
2
2
  import { a as OperationType, i as ErrorResponse$1, n as ProcessExitedBeforeReadyContext, o as ErrorCode, r as ProcessReadyTimeoutContext } from "./contexts-CdrlvHWK.js";
3
3
 
4
4
  //#region ../shared/dist/request-types.d.ts
@@ -15,7 +15,7 @@ interface ExecuteRequest {
15
15
  sessionId?: string;
16
16
  background?: boolean;
17
17
  timeoutMs?: number;
18
- env?: Record<string, string>;
18
+ env?: Record<string, string | undefined>;
19
19
  cwd?: string;
20
20
  }
21
21
  /**
@@ -27,11 +27,18 @@ interface StartProcessRequest {
27
27
  sessionId?: string;
28
28
  processId?: string;
29
29
  timeoutMs?: number;
30
- env?: Record<string, string>;
30
+ env?: Record<string, string | undefined>;
31
31
  cwd?: string;
32
32
  encoding?: string;
33
33
  autoCleanup?: boolean;
34
34
  }
35
+ /**
36
+ * Request to expose a port
37
+ */
38
+ interface ExposePortRequest {
39
+ port: number;
40
+ name?: string;
41
+ }
35
42
  //#endregion
36
43
  //#region src/errors/classes.d.ts
37
44
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":["ExecuteRequest","Record","StartProcessRequest","ReadFileRequest","WriteFileRequest","DeleteFileRequest","RenameFileRequest","MoveFileRequest","MkdirRequest","FileExistsRequest","ExposePortRequest","GitCheckoutRequest","ListFilesRequest","SessionCreateRequest","SessionDeleteRequest"],"sources":["../../shared/dist/request-types.d.ts","../src/errors/classes.ts","../src/file-stream.ts","../src/interpreter.ts","../src/request-handler.ts","../src/sse-parser.ts","../src/storage-mount/errors.ts"],"sourcesContent":["/**\n * Request types for API calls to the container\n * Single source of truth for the contract between SDK clients and container handlers\n */\n/**\n * Request to execute a command\n */\nexport interface ExecuteRequest {\n command: string;\n sessionId?: string;\n background?: boolean;\n timeoutMs?: number;\n env?: Record<string, string>;\n cwd?: string;\n}\n/**\n * Request to start a background process\n * Uses flat structure consistent with other endpoints\n */\nexport interface StartProcessRequest {\n command: string;\n sessionId?: string;\n processId?: string;\n timeoutMs?: number;\n env?: Record<string, string>;\n cwd?: string;\n encoding?: string;\n autoCleanup?: boolean;\n}\n/**\n * Request to read a file\n */\nexport interface ReadFileRequest {\n path: string;\n encoding?: string;\n sessionId?: string;\n}\n/**\n * Request to write a file\n */\nexport interface WriteFileRequest {\n path: string;\n content: string;\n encoding?: string;\n sessionId?: string;\n}\n/**\n * Request to delete a file\n */\nexport interface DeleteFileRequest {\n path: string;\n sessionId?: string;\n}\n/**\n * Request to rename a file\n */\nexport interface RenameFileRequest {\n oldPath: string;\n newPath: string;\n sessionId?: string;\n}\n/**\n * Request to move a file\n */\nexport interface MoveFileRequest {\n sourcePath: string;\n destinationPath: string;\n sessionId?: string;\n}\n/**\n * Request to create a directory\n */\nexport interface MkdirRequest {\n path: string;\n recursive?: boolean;\n sessionId?: string;\n}\n/**\n * Request to check if a file or directory exists\n */\nexport interface FileExistsRequest {\n path: string;\n sessionId?: string;\n}\n/**\n * Request to expose a port\n */\nexport interface ExposePortRequest {\n port: number;\n name?: string;\n}\n/**\n * Request to clone a Git repository\n */\nexport interface GitCheckoutRequest {\n repoUrl: string;\n branch?: string;\n targetDir?: string;\n sessionId?: string;\n /** Clone depth for shallow clones (e.g., 1 for latest commit only) */\n depth?: number;\n}\n/**\n * Request to list files in a directory\n */\nexport interface ListFilesRequest {\n path: string;\n options?: {\n recursive?: boolean;\n includeHidden?: boolean;\n };\n sessionId?: string;\n}\n/**\n * Request to create a session\n */\nexport interface SessionCreateRequest {\n id?: string;\n name?: string;\n env?: Record<string, string>;\n cwd?: string;\n}\n/**\n * Request to delete a session\n */\nexport interface SessionDeleteRequest {\n sessionId: string;\n}\n//# sourceMappingURL=request-types.d.ts.map"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":["ExecuteRequest","Record","StartProcessRequest","ReadFileRequest","WriteFileRequest","DeleteFileRequest","RenameFileRequest","MoveFileRequest","MkdirRequest","FileExistsRequest","ExposePortRequest","GitCheckoutRequest","ListFilesRequest","SessionCreateRequest","SessionDeleteRequest"],"sources":["../../shared/dist/request-types.d.ts","../src/errors/classes.ts","../src/file-stream.ts","../src/interpreter.ts","../src/request-handler.ts","../src/sse-parser.ts","../src/storage-mount/errors.ts"],"sourcesContent":["/**\n * Request types for API calls to the container\n * Single source of truth for the contract between SDK clients and container handlers\n */\n/**\n * Request to execute a command\n */\nexport interface ExecuteRequest {\n command: string;\n sessionId?: string;\n background?: boolean;\n timeoutMs?: number;\n env?: Record<string, string | undefined>;\n cwd?: string;\n}\n/**\n * Request to start a background process\n * Uses flat structure consistent with other endpoints\n */\nexport interface StartProcessRequest {\n command: string;\n sessionId?: string;\n processId?: string;\n timeoutMs?: number;\n env?: Record<string, string | undefined>;\n cwd?: string;\n encoding?: string;\n autoCleanup?: boolean;\n}\n/**\n * Request to read a file\n */\nexport interface ReadFileRequest {\n path: string;\n encoding?: string;\n sessionId?: string;\n}\n/**\n * Request to write a file\n */\nexport interface WriteFileRequest {\n path: string;\n content: string;\n encoding?: string;\n sessionId?: string;\n}\n/**\n * Request to delete a file\n */\nexport interface DeleteFileRequest {\n path: string;\n sessionId?: string;\n}\n/**\n * Request to rename a file\n */\nexport interface RenameFileRequest {\n oldPath: string;\n newPath: string;\n sessionId?: string;\n}\n/**\n * Request to move a file\n */\nexport interface MoveFileRequest {\n sourcePath: string;\n destinationPath: string;\n sessionId?: string;\n}\n/**\n * Request to create a directory\n */\nexport interface MkdirRequest {\n path: string;\n recursive?: boolean;\n sessionId?: string;\n}\n/**\n * Request to check if a file or directory exists\n */\nexport interface FileExistsRequest {\n path: string;\n sessionId?: string;\n}\n/**\n * Request to expose a port\n */\nexport interface ExposePortRequest {\n port: number;\n name?: string;\n}\n/**\n * Request to clone a Git repository\n */\nexport interface GitCheckoutRequest {\n repoUrl: string;\n branch?: string;\n targetDir?: string;\n sessionId?: string;\n /** Clone depth for shallow clones (e.g., 1 for latest commit only) */\n depth?: number;\n}\n/**\n * Request to list files in a directory\n */\nexport interface ListFilesRequest {\n path: string;\n options?: {\n recursive?: boolean;\n includeHidden?: boolean;\n };\n sessionId?: string;\n}\n/**\n * Request to create a session\n */\nexport interface SessionCreateRequest {\n id?: string;\n name?: string;\n env?: Record<string, string | undefined>;\n cwd?: string;\n}\n/**\n * Request to delete a session\n */\nexport interface SessionDeleteRequest {\n sessionId: string;\n}\n//# sourceMappingURL=request-types.d.ts.map"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as isExecResult, c as shellEscape, d as TraceContext, f as Execution, g as getEnvString, h as extractRepoName, i as isWSStreamChunk, l as createLogger, m as GitLogger, n as isWSError, o as isProcess, p as ResultImpl, r as isWSResponse, s as isProcessStatus, t as generateRequestId, u as createNoOpLogger } from "./dist-c_xYW5i_.js";
1
+ import { _ as getEnvString, a as isExecResult, c as shellEscape, d as TraceContext, f as Execution, g as filterEnvVars, h as extractRepoName, i as isWSStreamChunk, l as createLogger, m as GitLogger, n as isWSError, o as isProcess, p as ResultImpl, r as isWSResponse, s as isProcessStatus, t as generateRequestId, u as createNoOpLogger, v as partitionEnvVars } from "./dist-BpbdH8ry.js";
2
2
  import { t as ErrorCode } from "./errors-BCXUmJUn.js";
3
3
  import { Container, getContainer, switchPort } from "@cloudflare/containers";
4
4
 
@@ -2273,21 +2273,29 @@ async function proxyToSandbox(request, env) {
2273
2273
  }
2274
2274
  }
2275
2275
  function extractSandboxRoute(url) {
2276
- const subdomainMatch = url.hostname.match(/^(\d{4,5})-([^.-][^.]*?[^.-]|[^.-])-([a-z0-9_-]{16})\.(.+)$/);
2277
- if (!subdomainMatch) return null;
2278
- const portStr = subdomainMatch[1];
2279
- const sandboxId = subdomainMatch[2];
2280
- const token = subdomainMatch[3];
2281
- subdomainMatch[4];
2276
+ const dotIndex = url.hostname.indexOf(".");
2277
+ if (dotIndex === -1) return null;
2278
+ const subdomain = url.hostname.slice(0, dotIndex);
2279
+ url.hostname.slice(dotIndex + 1);
2280
+ const firstHyphen = subdomain.indexOf("-");
2281
+ if (firstHyphen === -1) return null;
2282
+ const portStr = subdomain.slice(0, firstHyphen);
2283
+ if (!/^\d{4,5}$/.test(portStr)) return null;
2282
2284
  const port = parseInt(portStr, 10);
2283
2285
  if (!validatePort(port)) return null;
2286
+ const rest = subdomain.slice(firstHyphen + 1);
2287
+ const lastHyphen = rest.lastIndexOf("-");
2288
+ if (lastHyphen === -1) return null;
2289
+ const sandboxId = rest.slice(0, lastHyphen);
2290
+ const token = rest.slice(lastHyphen + 1);
2291
+ if (!/^[a-z0-9_]+$/.test(token) || token.length === 0 || token.length > 63) return null;
2292
+ if (sandboxId.length === 0 || sandboxId.length > 63) return null;
2284
2293
  let sanitizedSandboxId;
2285
2294
  try {
2286
2295
  sanitizedSandboxId = sanitizeSandboxId(sandboxId);
2287
- } catch (error) {
2296
+ } catch {
2288
2297
  return null;
2289
2298
  }
2290
- if (sandboxId.length > 63) return null;
2291
2299
  return {
2292
2300
  port,
2293
2301
  sandboxId: sanitizedSandboxId,
@@ -2540,7 +2548,7 @@ function buildS3fsSource(bucket, prefix) {
2540
2548
  * This file is auto-updated by .github/changeset-version.ts during releases
2541
2549
  * DO NOT EDIT MANUALLY - Changes will be overwritten on the next version bump
2542
2550
  */
2543
- const SDK_VERSION = "0.6.11";
2551
+ const SDK_VERSION = "0.7.0";
2544
2552
 
2545
2553
  //#endregion
2546
2554
  //#region src/sandbox.ts
@@ -2657,14 +2665,23 @@ var Sandbox = class extends Container {
2657
2665
  await this.ctx.storage.put("keepAliveEnabled", keepAlive);
2658
2666
  }
2659
2667
  async setEnvVars(envVars) {
2668
+ const { toSet, toUnset } = partitionEnvVars(envVars);
2669
+ for (const key of toUnset) delete this.envVars[key];
2660
2670
  this.envVars = {
2661
2671
  ...this.envVars,
2662
- ...envVars
2672
+ ...toSet
2663
2673
  };
2664
- if (this.defaultSession) for (const [key, value] of Object.entries(envVars)) {
2665
- const exportCommand = `export ${key}='${value.replace(/'/g, "'\\''")}'`;
2666
- const result = await this.client.commands.execute(exportCommand, this.defaultSession);
2667
- if (result.exitCode !== 0) throw new Error(`Failed to set ${key}: ${result.stderr || "Unknown error"}`);
2674
+ if (this.defaultSession) {
2675
+ for (const key of toUnset) {
2676
+ const unsetCommand = `unset ${key}`;
2677
+ const result = await this.client.commands.execute(unsetCommand, this.defaultSession);
2678
+ if (result.exitCode !== 0) throw new Error(`Failed to unset ${key}: ${result.stderr || "Unknown error"}`);
2679
+ }
2680
+ for (const [key, value] of Object.entries(toSet)) {
2681
+ const exportCommand = `export ${key}=${shellEscape(value)}`;
2682
+ const result = await this.client.commands.execute(exportCommand, this.defaultSession);
2683
+ if (result.exitCode !== 0) throw new Error(`Failed to set ${key}: ${result.stderr || "Unknown error"}`);
2684
+ }
2668
2685
  }
2669
2686
  }
2670
2687
  /**
@@ -3422,7 +3439,7 @@ var Sandbox = class extends Container {
3422
3439
  const requestOptions = {
3423
3440
  ...options?.processId !== void 0 && { processId: options.processId },
3424
3441
  ...options?.timeout !== void 0 && { timeoutMs: options.timeout },
3425
- ...options?.env !== void 0 && { env: options.env },
3442
+ ...options?.env !== void 0 && { env: filterEnvVars(options.env) },
3426
3443
  ...options?.cwd !== void 0 && { cwd: options.cwd },
3427
3444
  ...options?.encoding !== void 0 && { encoding: options.encoding },
3428
3445
  ...options?.autoCleanup !== void 0 && { autoCleanup: options.autoCleanup }
@@ -3590,6 +3607,30 @@ var Sandbox = class extends Container {
3590
3607
  const session = sessionId ?? await this.ensureDefaultSession();
3591
3608
  return this.client.files.exists(path, session);
3592
3609
  }
3610
+ /**
3611
+ * Expose a port and get a preview URL for accessing services running in the sandbox
3612
+ *
3613
+ * @param port - Port number to expose (1024-65535)
3614
+ * @param options - Configuration options
3615
+ * @param options.hostname - Your Worker's domain name (required for preview URL construction)
3616
+ * @param options.name - Optional friendly name for the port
3617
+ * @param options.token - Optional custom token for the preview URL (1-16 characters: lowercase letters, numbers, hyphens, underscores)
3618
+ * If not provided, a random 16-character token will be generated automatically
3619
+ * @returns Preview URL information including the full URL, port number, and optional name
3620
+ *
3621
+ * @example
3622
+ * // With auto-generated token
3623
+ * const { url } = await sandbox.exposePort(8080, { hostname: 'example.com' });
3624
+ * // url: https://8080-sandbox-id-abc123random4567.example.com
3625
+ *
3626
+ * @example
3627
+ * // With custom token for stable URLs across deployments
3628
+ * const { url } = await sandbox.exposePort(8080, {
3629
+ * hostname: 'example.com',
3630
+ * token: 'my-token-v1'
3631
+ * });
3632
+ * // url: https://8080-sandbox-id-my-token-v1.example.com
3633
+ */
3593
3634
  async exposePort(port, options) {
3594
3635
  if (options.hostname.endsWith(".workers.dev")) throw new CustomDomainRequiredError({
3595
3636
  code: ErrorCode.CUSTOM_DOMAIN_REQUIRED,
@@ -3598,11 +3639,17 @@ var Sandbox = class extends Container {
3598
3639
  httpStatus: 400,
3599
3640
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
3600
3641
  });
3601
- const sessionId = await this.ensureDefaultSession();
3602
- await this.client.ports.exposePort(port, sessionId, options?.name);
3603
3642
  if (!this.sandboxName) throw new Error("Sandbox name not available. Ensure sandbox is accessed through getSandbox()");
3604
- const token = this.generatePortToken();
3643
+ let token;
3644
+ if (options.token !== void 0) {
3645
+ this.validateCustomToken(options.token);
3646
+ token = options.token;
3647
+ } else token = this.generatePortToken();
3605
3648
  const tokens = await this.ctx.storage.get("portTokens") || {};
3649
+ const existingPort = Object.entries(tokens).find(([p, t]) => t === token && p !== port.toString());
3650
+ if (existingPort) throw new SecurityError(`Token '${token}' is already in use by port ${existingPort[0]}. Please use a different token.`);
3651
+ const sessionId = await this.ensureDefaultSession();
3652
+ await this.client.ports.exposePort(port, sessionId, options?.name);
3606
3653
  tokens[port.toString()] = token;
3607
3654
  await this.ctx.storage.put("portTokens", tokens);
3608
3655
  return {
@@ -3652,12 +3699,21 @@ var Sandbox = class extends Container {
3652
3699
  this.logger.error("Port is exposed but has no token - bug detected", void 0, { port });
3653
3700
  return false;
3654
3701
  }
3655
- return storedToken === token;
3702
+ if (storedToken.length !== token.length) return false;
3703
+ const encoder = new TextEncoder();
3704
+ const a = encoder.encode(storedToken);
3705
+ const b = encoder.encode(token);
3706
+ return crypto.subtle.timingSafeEqual(a, b);
3707
+ }
3708
+ validateCustomToken(token) {
3709
+ if (token.length === 0) throw new SecurityError(`Custom token cannot be empty.`);
3710
+ if (token.length > 16) throw new SecurityError(`Custom token too long. Maximum 16 characters allowed. Received: ${token.length} characters.`);
3711
+ if (!/^[a-z0-9_]+$/.test(token)) throw new SecurityError(`Custom token must contain only lowercase letters (a-z), numbers (0-9), and underscores (_). Invalid token provided.`);
3656
3712
  }
3657
3713
  generatePortToken() {
3658
3714
  const array = new Uint8Array(12);
3659
3715
  crypto.getRandomValues(array);
3660
- return btoa(String.fromCharCode(...array)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "").toLowerCase();
3716
+ return btoa(String.fromCharCode(...array)).replace(/\+/g, "_").replace(/\//g, "_").replace(/=/g, "").toLowerCase();
3661
3717
  }
3662
3718
  constructPreviewUrl(port, sandboxId, hostname, token) {
3663
3719
  if (!validatePort(port)) throw new SecurityError(`Invalid port number: ${port}. Must be between 1024-65535 and not reserved.`);
@@ -3690,11 +3746,11 @@ var Sandbox = class extends Container {
3690
3746
  */
3691
3747
  async createSession(options) {
3692
3748
  const sessionId = options?.id || `session-${Date.now()}`;
3693
- const mergedEnv = {
3749
+ const filteredEnv = filterEnvVars({
3694
3750
  ...this.envVars,
3695
3751
  ...options?.env ?? {}
3696
- };
3697
- const envPayload = Object.keys(mergedEnv).length > 0 ? mergedEnv : void 0;
3752
+ });
3753
+ const envPayload = Object.keys(filteredEnv).length > 0 ? filteredEnv : void 0;
3698
3754
  await this.client.utils.createSession({
3699
3755
  id: sessionId,
3700
3756
  ...envPayload && { env: envPayload },
@@ -3774,9 +3830,15 @@ var Sandbox = class extends Container {
3774
3830
  sessionId
3775
3831
  }),
3776
3832
  setEnvVars: async (envVars) => {
3833
+ const { toSet, toUnset } = partitionEnvVars(envVars);
3777
3834
  try {
3778
- for (const [key, value] of Object.entries(envVars)) {
3779
- const exportCommand = `export ${key}='${value.replace(/'/g, "'\\''")}'`;
3835
+ for (const key of toUnset) {
3836
+ const unsetCommand = `unset ${key}`;
3837
+ const result = await this.client.commands.execute(unsetCommand, sessionId);
3838
+ if (result.exitCode !== 0) throw new Error(`Failed to unset ${key}: ${result.stderr || "Unknown error"}`);
3839
+ }
3840
+ for (const [key, value] of Object.entries(toSet)) {
3841
+ const exportCommand = `export ${key}=${shellEscape(value)}`;
3780
3842
  const result = await this.client.commands.execute(exportCommand, sessionId);
3781
3843
  if (result.exitCode !== 0) throw new Error(`Failed to set ${key}: ${result.stderr || "Unknown error"}`);
3782
3844
  }