@cloudflare/sandbox 0.13.0-next.776.1 → 0.13.0-next.797.1
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/bridge/index.js +24 -8
- package/dist/bridge/index.js.map +1 -1
- package/dist/{dist-Duor5GbS.js → dist-n_eniPAR.js} +8 -46
- package/dist/dist-n_eniPAR.js.map +1 -0
- package/dist/extensions/index.d.ts +2 -2
- package/dist/extensions/index.js +2 -2
- package/dist/{extensions-CFB2xHqY.js → extensions-Be5HnDGt.js} +2 -2
- package/dist/{extensions-CFB2xHqY.js.map → extensions-Be5HnDGt.js.map} +1 -1
- package/dist/{filesystem-BWAZCZER.d.ts → filesystem-Y5aF3nmJ.d.ts} +7 -3
- package/dist/filesystem-Y5aF3nmJ.d.ts.map +1 -0
- package/dist/git/index.d.ts +2 -2
- package/dist/git/index.js +2 -2
- package/dist/{index-Bs4bqXDR.d.ts → index-DfXx3uZL.d.ts} +2 -2
- package/dist/{index-Bs4bqXDR.d.ts.map → index-DfXx3uZL.d.ts.map} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/interpreter/index.d.ts +2 -2
- package/dist/interpreter/index.js +2 -2
- package/dist/openai/index.d.ts +2 -2
- package/dist/openai/index.d.ts.map +1 -1
- package/dist/openai/index.js +10 -34
- package/dist/openai/index.js.map +1 -1
- package/dist/opencode/index.d.ts +2 -2
- package/dist/opencode/index.js +2 -2
- package/dist/{sandbox-cmlgGVYX.js → sandbox-BEhPgFZx.js} +127 -48
- package/dist/sandbox-BEhPgFZx.js.map +1 -0
- package/dist/{sandbox-BbAabq93.d.ts → sandbox-CBkS3tGv.d.ts} +2 -2
- package/dist/{sandbox-BbAabq93.d.ts.map → sandbox-CBkS3tGv.d.ts.map} +1 -1
- package/package.json +1 -1
- package/dist/dist-Duor5GbS.js.map +0 -1
- package/dist/filesystem-BWAZCZER.d.ts.map +0 -1
- package/dist/sandbox-cmlgGVYX.js.map +0 -1
|
@@ -117,24 +117,6 @@ function redactSensitiveParams(input) {
|
|
|
117
117
|
function redactCommand(command) {
|
|
118
118
|
return redactSensitiveParams(redactCredentials(command));
|
|
119
119
|
}
|
|
120
|
-
/**
|
|
121
|
-
* Truncate a string for log output with a truncation indicator
|
|
122
|
-
*
|
|
123
|
-
* @param value - String to potentially truncate
|
|
124
|
-
* @param maxLen - Maximum length before truncation (default 120)
|
|
125
|
-
* @returns Object with truncated value and boolean flag
|
|
126
|
-
*/
|
|
127
|
-
function truncateForLog(value, maxLen = 120) {
|
|
128
|
-
if (value.length <= maxLen) return {
|
|
129
|
-
value,
|
|
130
|
-
truncated: false
|
|
131
|
-
};
|
|
132
|
-
const cutoff = Math.max(0, maxLen - 3);
|
|
133
|
-
return {
|
|
134
|
-
value: `${value.substring(0, cutoff)}...`,
|
|
135
|
-
truncated: true
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
120
|
|
|
139
121
|
//#endregion
|
|
140
122
|
//#region ../shared/dist/git.js
|
|
@@ -198,28 +180,16 @@ function sanitizeError(error) {
|
|
|
198
180
|
return sanitized;
|
|
199
181
|
}
|
|
200
182
|
/**
|
|
201
|
-
* Sanitize and prepare payload fields for both message building and context emission.
|
|
202
|
-
* Called once by logCanonicalEvent to avoid double-redaction.
|
|
203
|
-
*/
|
|
204
|
-
function sanitizePayload(payload) {
|
|
205
|
-
if (payload.command === void 0) return { commandTruncated: false };
|
|
206
|
-
const { value, truncated } = truncateForLog(redactCommand(payload.command));
|
|
207
|
-
return {
|
|
208
|
-
sanitizedCommand: value,
|
|
209
|
-
commandTruncated: truncated
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
183
|
* Build a human-readable canonical event message for dashboards and log viewers.
|
|
214
184
|
*
|
|
215
185
|
* Format: `{event} {outcome} {key_context} [— {reason}] ({durationMs}ms[, {sizeBytes}B])`
|
|
216
186
|
*
|
|
217
|
-
* The if/else chain for key context has implicit priority:
|
|
187
|
+
* The if/else chain for key context has implicit priority: argv0 > path >
|
|
218
188
|
* port > repoUrl > pid. If a payload has multiple, only the highest-priority
|
|
219
189
|
* one appears in the message. All fields are still present as discrete
|
|
220
190
|
* queryable keys in the structured log context.
|
|
221
191
|
*/
|
|
222
|
-
function buildMessage(payload
|
|
192
|
+
function buildMessage(payload) {
|
|
223
193
|
const { event } = payload;
|
|
224
194
|
if (event === "version.check") {
|
|
225
195
|
const parts$1 = ["version.check"];
|
|
@@ -229,11 +199,8 @@ function buildMessage(payload, sanitizedCommand) {
|
|
|
229
199
|
return parts$1.join(" ");
|
|
230
200
|
}
|
|
231
201
|
const parts = [event, payload.outcome];
|
|
232
|
-
if (
|
|
233
|
-
else if (payload.
|
|
234
|
-
const { value } = truncateForLog(redactCommand(payload.command));
|
|
235
|
-
parts.push(value);
|
|
236
|
-
} else if (payload.path !== void 0) parts.push(payload.path);
|
|
202
|
+
if (payload.argv0 !== void 0) parts.push(payload.argv0);
|
|
203
|
+
else if (payload.path !== void 0) parts.push(payload.path);
|
|
237
204
|
else if (payload.port !== void 0) parts.push(String(payload.port));
|
|
238
205
|
else if (payload.repoUrl !== void 0) {
|
|
239
206
|
let gitContext = payload.repoUrl;
|
|
@@ -261,8 +228,8 @@ function buildMessage(payload, sanitizedCommand) {
|
|
|
261
228
|
/**
|
|
262
229
|
* Log a canonical event — the single entry point for all structured operational events.
|
|
263
230
|
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
231
|
+
* Redacts error text, builds the message, selects log level from outcome, and
|
|
232
|
+
* emits a structured log entry with the full payload as context.
|
|
266
233
|
*/
|
|
267
234
|
function logCanonicalEvent(logger, payload, options) {
|
|
268
235
|
const resolvedErrorMessage = payload.errorMessage ?? payload.error?.message;
|
|
@@ -271,17 +238,12 @@ function logCanonicalEvent(logger, payload, options) {
|
|
|
271
238
|
...payload,
|
|
272
239
|
errorMessage: sanitizedErrorMessage
|
|
273
240
|
} : payload;
|
|
274
|
-
const
|
|
275
|
-
const message = buildMessage(enrichedPayload, sanitizedCommand);
|
|
241
|
+
const message = buildMessage(enrichedPayload);
|
|
276
242
|
const context = {};
|
|
277
243
|
for (const [key, value] of Object.entries(enrichedPayload)) {
|
|
278
244
|
if (key === "error") continue;
|
|
279
245
|
context[key] = value;
|
|
280
246
|
}
|
|
281
|
-
if (sanitizedCommand !== void 0) {
|
|
282
|
-
context.command = sanitizedCommand;
|
|
283
|
-
if (commandTruncated) context.commandTruncated = true;
|
|
284
|
-
}
|
|
285
247
|
const level = resolveLogLevel(enrichedPayload, options);
|
|
286
248
|
if (level === "error") logger.error(message, sanitizeError(payload.error), context);
|
|
287
249
|
else if (level === "warn") logger.warn(message, context);
|
|
@@ -749,4 +711,4 @@ function parseSSEFrames(buffer, currentEvent = { data: [] }) {
|
|
|
749
711
|
|
|
750
712
|
//#endregion
|
|
751
713
|
export { TraceContext as a, extractRepoName as c, partitionEnvVars as d, createNoOpLogger as i, redactCommand as l, EXTENSION_TARBALL_REQUIRED as n, logCanonicalEvent as o, createLogger as r, DEFAULT_GIT_CLONE_TIMEOUT_MS as s, parseSSEFrames as t, getEnvString as u };
|
|
752
|
-
//# sourceMappingURL=dist-
|
|
714
|
+
//# sourceMappingURL=dist-n_eniPAR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dist-n_eniPAR.js","names":["parts","LogLevelEnum","LogLevelEnum"],"sources":["../../shared/dist/env.js","../../shared/dist/logger/sanitize.js","../../shared/dist/git.js","../../shared/dist/logger/canonical.js","../../shared/dist/logger/types.js","../../shared/dist/logger/logger.js","../../shared/dist/logger/trace-context.js","../../shared/dist/logger/index.js","../../shared/dist/rpc-types.js","../../shared/dist/sse.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 * Log-only sanitization helpers\n *\n * These functions redact sensitive values for logging output.\n * They MUST NOT be used to mutate command strings before execution.\n */\n/**\n * Sensitive query parameter names to redact from URLs.\n * Anchored to query string context ([?&]) to avoid matching path segments.\n * Value matching stops at & and common URL/command delimiters.\n */\nconst SENSITIVE_PARAMS = /([?&])(X-Amz-Credential|X-Amz-Signature|X-Amz-Security-Token|token|secret|password)=[^&\\s\"'`<>]*/gi;\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.\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 * Redact sensitive query parameters from URLs\n *\n * Strips X-Amz-Credential, X-Amz-Signature, X-Amz-Security-Token,\n * token, secret, and password query params from URLs. Returns\n * non-URL strings unchanged.\n *\n * @param input - String that may contain URLs with sensitive params\n * @returns String with sensitive params replaced by REDACTED\n */\nexport function redactSensitiveParams(input) {\n if (!input.includes('?') || !input.includes('='))\n return input;\n return input.replace(SENSITIVE_PARAMS, '$1$2=REDACTED');\n}\n/**\n * Redact sensitive data from a command string for logging\n *\n * Composes redactCredentials (URL credentials) and redactSensitiveParams\n * (presigned URL query params). For log values only — never mutate\n * command strings before execution.\n *\n * @param command - Command string to sanitize for logging\n * @returns Sanitized command string\n */\nexport function redactCommand(command) {\n return redactSensitiveParams(redactCredentials(command));\n}\n","import { redactCommand } from './logger/sanitize.js';\n/**\n * Fallback repository name used when URL parsing fails\n */\nexport const FALLBACK_REPO_NAME = 'repository';\n/** Default wall-clock timeout in milliseconds for git clone operations. */\nexport const DEFAULT_GIT_CLONE_TIMEOUT_MS = 600_000;\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 * 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 redactCommand(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(redactCommand(error.message));\n sanitized.name = error.name;\n if (error.stack) {\n sanitized.stack = redactCommand(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","import { redactCommand } from './sanitize.js';\n/** Events that are low-value at info on success */\nconst DEBUG_ON_SUCCESS = new Set([\n 'file.read',\n 'file.write',\n 'file.delete',\n 'file.mkdir'\n]);\nexport function resolveLogLevel(payload, options) {\n if (payload.outcome === 'error')\n return 'error';\n if (options?.successLevel)\n return options.successLevel;\n if (payload.origin === 'internal')\n return 'debug';\n if (DEBUG_ON_SUCCESS.has(payload.event))\n return 'debug';\n return 'info';\n}\n/**\n * Sanitize an Error object by redacting sensitive data from message and stack.\n * Produces a copy so the caller's original Error is not mutated.\n */\nfunction sanitizeError(error) {\n if (!error)\n return undefined;\n const sanitized = new Error(redactCommand(error.message));\n sanitized.name = error.name;\n sanitized.stack = error.stack ? redactCommand(error.stack) : undefined;\n return sanitized;\n}\n/**\n * Build a human-readable canonical event message for dashboards and log viewers.\n *\n * Format: `{event} {outcome} {key_context} [— {reason}] ({durationMs}ms[, {sizeBytes}B])`\n *\n * The if/else chain for key context has implicit priority: argv0 > path >\n * port > repoUrl > pid. If a payload has multiple, only the highest-priority\n * one appears in the message. All fields are still present as discrete\n * queryable keys in the structured log context.\n */\nexport function buildMessage(payload) {\n const { event } = payload;\n // version.check has its own format: no outcome, no duration\n if (event === 'version.check') {\n const parts = ['version.check'];\n if (payload.sdkVersion)\n parts.push(`sdk=${payload.sdkVersion}`);\n if (payload.containerVersion)\n parts.push(`container=${payload.containerVersion}`);\n if (payload.versionOutcome && payload.versionOutcome !== 'compatible') {\n parts.push(`(${payload.versionOutcome})`);\n }\n return parts.join(' ');\n }\n const parts = [event, payload.outcome];\n // Key context — highest priority field shown in message\n if (payload.argv0 !== undefined) {\n parts.push(payload.argv0);\n }\n else if (payload.path !== undefined) {\n parts.push(payload.path);\n }\n else if (payload.port !== undefined) {\n parts.push(String(payload.port));\n }\n else if (payload.repoUrl !== undefined) {\n let gitContext = payload.repoUrl;\n if (payload.branch !== undefined) {\n gitContext += ` ${payload.branch}`;\n }\n parts.push(gitContext);\n }\n else if (payload.pid !== undefined) {\n parts.push(String(payload.pid));\n }\n else if (payload.backupId !== undefined) {\n parts.push(payload.backupId);\n }\n else if (payload.repoPath !== undefined) {\n let gitContext = payload.repoPath;\n if (payload.branch !== undefined) {\n gitContext += ` branch=${payload.branch}`;\n }\n parts.push(gitContext);\n }\n else if (payload.mountsProcessed !== undefined) {\n let destroyContext = `${payload.mountsProcessed} mounts`;\n if (payload.mountFailures)\n destroyContext += `, ${payload.mountFailures} failed`;\n parts.push(destroyContext);\n }\n else if (payload.mountPath !== undefined) {\n parts.push(payload.mountPath);\n }\n // Error reason after em-dash\n if (payload.outcome === 'error') {\n if (payload.errorMessage !== undefined) {\n parts.push(`\\u2014 ${payload.errorMessage}`);\n }\n else if (payload.exitCode !== undefined) {\n parts.push(`\\u2014 exitCode=${payload.exitCode}`);\n }\n }\n // Duration suffix (and optional size)\n const durationSuffix = payload.sizeBytes !== undefined\n ? `(${payload.durationMs}ms, ${payload.sizeBytes}B)`\n : `(${payload.durationMs}ms)`;\n parts.push(durationSuffix);\n return parts.join(' ');\n}\n/**\n * Log a canonical event — the single entry point for all structured operational events.\n *\n * Redacts error text, builds the message, selects log level from outcome, and\n * emits a structured log entry with the full payload as context.\n */\nexport function logCanonicalEvent(logger, payload, options) {\n // Auto-derive errorMessage from error.message when not explicitly set,\n // then sanitize to prevent credential leaks (e.g., presigned URLs in error strings)\n const resolvedErrorMessage = payload.errorMessage ?? payload.error?.message;\n const sanitizedErrorMessage = resolvedErrorMessage\n ? redactCommand(resolvedErrorMessage)\n : undefined;\n const enrichedPayload = sanitizedErrorMessage !== undefined\n ? { ...payload, errorMessage: sanitizedErrorMessage }\n : payload;\n const message = buildMessage(enrichedPayload);\n // Build context from enriched payload, excluding the error object (passed separately)\n const context = {};\n for (const [key, value] of Object.entries(enrichedPayload)) {\n if (key === 'error')\n continue;\n context[key] = value;\n }\n const level = resolveLogLevel(enrichedPayload, options);\n if (level === 'error') {\n logger.error(message, sanitizeError(payload.error), context);\n }\n else if (level === 'warn') {\n logger.warn(message, context);\n }\n else if (level === 'debug') {\n logger.debug(message, context);\n }\n else {\n logger.info(message, context);\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 outputMode;\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 outputMode How log entries are formatted and emitted (default: 'structured')\n */\n constructor(baseContext, minLevel = LogLevelEnum.INFO, outputMode = 'structured') {\n this.baseContext = baseContext;\n this.minLevel = minLevel;\n this.outputMode = outputMode;\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.outputMode);\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 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 using the configured output mode\n */\n output(consoleFn, data) {\n switch (this.outputMode) {\n case 'pretty':\n this.outputPretty(consoleFn, data);\n break;\n case 'json-line':\n this.outputJsonLine(consoleFn, data);\n break;\n case 'structured':\n this.outputStructured(consoleFn, data);\n break;\n }\n }\n /**\n * Output as JSON string (container stdout — parsed by Containers pipeline)\n */\n outputJsonLine(consoleFn, data) {\n consoleFn(JSON.stringify(data));\n }\n /**\n * Output as raw object (Workers/DOs — Workers Logs auto-indexes fields)\n */\n outputStructured(consoleFn, data) {\n consoleFn(data);\n }\n /**\n * Output as pretty-printed, colored text (development)\n *\n * Each log event is a single consoleFn() call so it appears as one entry\n * in the Cloudflare dashboard. Context is rendered inline as compact key=value pairs.\n *\n * Format: LEVEL [component] message trace=tr_... key=value key=value\n */\n outputPretty(consoleFn, data) {\n const { level, message: msg, timestamp, traceId, component, sandboxId, processId, commandId, durationMs, serviceVersion, instanceId, error, ...rest } = data;\n const levelStr = String(level || 'INFO').toUpperCase();\n const levelColor = this.getLevelColor(levelStr);\n const componentBadge = component ? `[${component}]` : '';\n const timeStr = timestamp\n ? `${COLORS.dim}${new Date(timestamp).toISOString().substring(11, 23)}${COLORS.reset} `\n : '';\n let logLine = `${timeStr}${levelColor}${levelStr.padEnd(5)}${COLORS.reset} ${componentBadge} ${msg}`;\n // Append all context as compact key=value pairs on the same line\n const pairs = [];\n if (traceId)\n pairs.push(`trace=${String(traceId).substring(0, 12)}`);\n if (commandId)\n pairs.push(`cmd=${String(commandId).substring(0, 12)}`);\n if (sandboxId)\n pairs.push(`sandbox=${sandboxId}`);\n if (processId)\n pairs.push(`proc=${processId}`);\n if (durationMs !== undefined)\n pairs.push(`dur=${durationMs}ms`);\n // Append remaining context fields inline\n for (const [key, value] of Object.entries(rest)) {\n if (value === undefined || value === null)\n continue;\n const v = typeof value === 'object'\n ? JSON.stringify(value)\n : this.sanitizePrettyValue(String(value));\n pairs.push(`${key}=${v}`);\n }\n // Append error info inline\n if (error && typeof error === 'object') {\n const errorObj = error;\n if (errorObj.name)\n pairs.push(`err.name=${this.sanitizePrettyValue(errorObj.name)}`);\n if (errorObj.message)\n pairs.push(`err.msg=${this.sanitizePrettyValue(errorObj.message)}`);\n if (errorObj.stack)\n pairs.push(`err.stack=${this.sanitizePrettyValue(errorObj.stack)}`);\n }\n if (pairs.length > 0) {\n logLine += ` ${COLORS.dim}${pairs.join(' ')}${COLORS.reset}`;\n }\n // Single consoleFn call = single log entry in the dashboard\n consoleFn(logLine);\n }\n /**\n * Collapse newlines so a single consoleFn() call stays on one line.\n * Cloudflare's log pipeline splits on literal newlines, which fragments\n * stack traces and multi-line error messages into separate entries.\n */\n sanitizePrettyValue(value) {\n return value.replace(/\\r/g, '\\\\r').replace(/\\n/g, '\\\\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 * - Three output modes: structured (Workers/DOs), json-line (container), pretty (local dev)\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({ 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 { buildMessage, logCanonicalEvent, resolveLogLevel } from './canonical.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 * sandboxId: this.id\n * });\n * ```\n */\nexport function createLogger(context) {\n const minLevel = getLogLevelFromEnv();\n const outputMode = getOutputMode(context.component);\n const baseContext = {\n ...context,\n traceId: context.traceId || TraceContext.generate(),\n component: context.component,\n serviceVersion: context.serviceVersion || getEnvVar('SANDBOX_VERSION') || undefined,\n instanceId: context.instanceId ||\n getEnvVar('HOSTNAME') ||\n getEnvVar('SANDBOX_INSTANCE_ID') ||\n undefined\n };\n return new CloudflareLogger(baseContext, minLevel, outputMode);\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 * Determine output mode based on component and environment:\n * - SANDBOX_LOG_FORMAT=pretty → 'pretty' for all components (local wrangler dev)\n * - Container/Executor without pretty → 'json-line' (Bun stdout → Containers pipeline)\n * - Everything else without pretty → 'structured' (Workers/DOs → Workers Logs)\n *\n * In local dev, setting SANDBOX_LOG_FORMAT=pretty gives readable terminal\n * output on both the DO side and container side. In production (where the\n * var isn't set), DOs emit structured objects and containers emit single-line\n * JSON — both queryable by their respective observability pipelines.\n */\nfunction getOutputMode(component) {\n const format = getEnvVar('SANDBOX_LOG_FORMAT');\n if (format?.toLowerCase() === 'pretty') {\n return 'pretty';\n }\n if (component === 'container' || component === 'executor') {\n return 'json-line';\n }\n return 'structured';\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 * Shared interface types for the container-control path.\n *\n * Defines the contract between the SDK control client and the container\n * control-plane API. The current wire implementation uses capnweb RPC.\n */\n/**\n * Error name thrown by the host's `connect` when it has not yet provisioned\n * the requested hash and the request did not carry tarball bytes. The SDK\n * recognises this name via `Error.name` and retries the connect with the\n * bytes attached. Kept as a string constant so it survives capnweb\n * cross-realm error reconstruction.\n */\nexport const EXTENSION_TARBALL_REQUIRED = 'ExtensionTarballRequired';\n","/**\n * Shared SSE parsing utilities.\n *\n * Parses SSE frames from arbitrary text chunks while preserving partial state\n * across chunk boundaries.\n */\n/**\n * Parse SSE frames from a buffer.\n *\n * Returns parsed events, remaining unparsed text, and the current partial event\n * so callers can continue parsing on the next chunk.\n */\nexport function parseSSEFrames(buffer, currentEvent = { data: [] }) {\n const events = [];\n let i = 0;\n while (i < buffer.length) {\n const newlineIndex = buffer.indexOf('\\n', i);\n if (newlineIndex === -1)\n break;\n const rawLine = buffer.substring(i, newlineIndex);\n const line = rawLine.endsWith('\\r') ? rawLine.slice(0, -1) : rawLine;\n i = newlineIndex + 1;\n if (line === '' && currentEvent.data.length > 0) {\n events.push({\n event: currentEvent.event,\n data: currentEvent.data.join('\\n')\n });\n currentEvent = { data: [] };\n continue;\n }\n if (line.startsWith('event:')) {\n const value = line.startsWith('event: ')\n ? line.substring(7)\n : line.substring(6);\n currentEvent.event = value;\n continue;\n }\n if (line.startsWith('data:')) {\n const value = line.startsWith('data: ')\n ? line.substring(6)\n : line.substring(5);\n currentEvent.data.push(value);\n }\n }\n return {\n events,\n remaining: buffer.substring(i),\n currentEvent\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import "../process-types-GStiZ8f8.js";
|
|
2
|
-
import "../filesystem-
|
|
3
|
-
import { a as ExtensionRuntimeControl, c as SandboxExtension, d as sandboxRuntimeCall, h as ExtensionPackage, i as ExtensionRuntimeCallbackResult, l as SandboxLike, m as ExtensionHealth, n as ExtensionRuntimeCall, o as HTTPAuthHostConfig, r as ExtensionRuntimeCallback, s as HTTPAuthInterceptorParams, t as ExtensionProcessSandbox, u as createExtensionProcessSandbox } from "../index-
|
|
2
|
+
import "../filesystem-Y5aF3nmJ.js";
|
|
3
|
+
import { a as ExtensionRuntimeControl, c as SandboxExtension, d as sandboxRuntimeCall, h as ExtensionPackage, i as ExtensionRuntimeCallbackResult, l as SandboxLike, m as ExtensionHealth, n as ExtensionRuntimeCall, o as HTTPAuthHostConfig, r as ExtensionRuntimeCallback, s as HTTPAuthInterceptorParams, t as ExtensionProcessSandbox, u as createExtensionProcessSandbox } from "../index-DfXx3uZL.js";
|
|
4
4
|
export { ExtensionHealth, ExtensionPackage, ExtensionProcessSandbox, ExtensionRuntimeCall, ExtensionRuntimeCallback, ExtensionRuntimeCallbackResult, ExtensionRuntimeControl, HTTPAuthHostConfig, HTTPAuthInterceptorParams, SandboxExtension, SandboxLike, createExtensionProcessSandbox, sandboxRuntimeCall };
|
package/dist/extensions/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "../errors-CXR0xBpw.js";
|
|
2
2
|
import "../errors-QYlSkVGz.js";
|
|
3
|
-
import "../dist-
|
|
4
|
-
import { n as createExtensionProcessSandbox, r as sandboxRuntimeCall, t as SandboxExtension } from "../extensions-
|
|
3
|
+
import "../dist-n_eniPAR.js";
|
|
4
|
+
import { n as createExtensionProcessSandbox, r as sandboxRuntimeCall, t as SandboxExtension } from "../extensions-Be5HnDGt.js";
|
|
5
5
|
|
|
6
6
|
export { SandboxExtension, createExtensionProcessSandbox, sandboxRuntimeCall };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as ErrorCode, n as getSuggestion, r as getHttpStatus } from "./errors-CXR0xBpw.js";
|
|
2
2
|
import { d as ProcessExitedBeforeLogError, f as ProcessExitedBeforeReadyError, g as ProcessWaitTimeoutError, l as ProcessAbortedError, m as ProcessReadyTimeoutError, t as createErrorFromResponse, tt as SandboxError, u as ProcessError } from "./errors-QYlSkVGz.js";
|
|
3
|
-
import { n as EXTENSION_TARBALL_REQUIRED } from "./dist-
|
|
3
|
+
import { n as EXTENSION_TARBALL_REQUIRED } from "./dist-n_eniPAR.js";
|
|
4
4
|
import { RpcTarget } from "cloudflare:workers";
|
|
5
5
|
|
|
6
6
|
//#region src/container-control/rpc-error.ts
|
|
@@ -1020,4 +1020,4 @@ async function sha256Hex(bytes) {
|
|
|
1020
1020
|
|
|
1021
1021
|
//#endregion
|
|
1022
1022
|
export { PullSubscriptionTarget as a, createSandboxProcess as i, createExtensionProcessSandbox as n, openRemoteSubscription as o, sandboxRuntimeCall as r, translateRPCError as s, SandboxExtension as t };
|
|
1023
|
-
//# sourceMappingURL=extensions-
|
|
1023
|
+
//# sourceMappingURL=extensions-Be5HnDGt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extensions-CFB2xHqY.js","names":["context","payload: RPCErrorPayload | undefined","kind: RPCTransportErrorKind","closeCode: number | undefined","closeReason: string | undefined","context: RPCTransportContext","interruptedContext: OperationInterruptedContext","#reader","#onRelease","#released","#release","subscription:\n | ProcessSubscriptionRPC<T>\n | ProcessPullSubscriptionRPC<T>\n | undefined","onAbort: (() => void) | undefined","onAbort","read: () => Promise<ReadableStreamReadResult<T>>","cancelReader: () => void","source: ReadableStream<T>","reader: ReadableStreamDefaultReader<T>","controller: ReadableStreamDefaultController<T> | undefined","timer: ReturnType<typeof setTimeout> | undefined","abortListener: (() => void) | undefined","competitors: Promise<T>[]","stdout: Uint8Array[]","stderr: Uint8Array[]","match","id: string","pid: number","capability: ProcessRPCDescriptor['capability']","#exitCodePromise","logStream: ReadableStream<ProcessLogEvent> | undefined","portReader: ReadableStreamDefaultReader<PortWatchEvent> | undefined","logReader: ReadableStreamDefaultReader<ProcessLogEvent> | undefined","reader: ReadableStreamDefaultReader<ProcessLogEvent> | undefined","sandboxRuntimeCall: unique symbol","#sandbox","#pkg","#requirePackage","#hashOnce","#connect","#hashPromise","current: object | null"],"sources":["../src/container-control/rpc-error.ts","../src/processes/remote-subscription.ts","../src/processes/process-waits.ts","../src/processes/process-output.ts","../src/processes/process-readiness.ts","../src/processes/wait-for-log.ts","../src/processes/sandbox-process.ts","../src/extensions/index.ts"],"sourcesContent":["/** Error translation for container control RPC calls. */\n\nimport {\n ErrorCode,\n type ErrorResponse,\n getHttpStatus,\n getSuggestion,\n type OperationInterruptedContext,\n type RPCTransportContext,\n type RPCTransportErrorKind\n} from '@repo/shared/errors';\nimport { createErrorFromResponse } from '../errors/adapter';\nimport { SandboxError } from '../errors/classes';\n\ninterface RPCErrorPayload {\n code: string;\n message: string;\n context?: Record<string, unknown>;\n}\n\nfunction isLocalSandboxError(\n error: Error\n): error is Error & { errorResponse: ErrorResponse } {\n if (!('errorResponse' in error)) return false;\n const response = error.errorResponse as Partial<ErrorResponse> | undefined;\n return (\n typeof response?.code === 'string' &&\n Object.hasOwn(ErrorCode, response.code) &&\n typeof response.message === 'string' &&\n typeof response.httpStatus === 'number' &&\n typeof response.timestamp === 'string' &&\n typeof response.context === 'object' &&\n response.context !== null\n );\n}\n\nexport interface RPCTranslationContext {\n operation?: string;\n translateTransportErrorsAsInterruptions?: boolean;\n}\n\nexport function translateRPCError(\n error: unknown,\n context: RPCTranslationContext = {}\n): never {\n if (error instanceof SandboxError) throw error;\n\n if (error instanceof Error) {\n if (isLocalSandboxError(error)) {\n throw error;\n }\n\n const propagated = error as Error & {\n code?: unknown;\n details?: unknown;\n };\n if (\n typeof propagated.code === 'string' &&\n Object.hasOwn(ErrorCode, propagated.code)\n ) {\n const code = propagated.code as ErrorCode;\n const context =\n propagated.details && typeof propagated.details === 'object'\n ? (propagated.details as Record<string, unknown>)\n : {};\n throw createErrorFromResponse({\n code,\n message: error.message,\n context,\n httpStatus: getHttpStatus(code),\n timestamp: new Date().toISOString()\n });\n }\n\n let payload: RPCErrorPayload | undefined;\n try {\n payload = JSON.parse(error.message) as RPCErrorPayload;\n } catch {}\n if (\n payload &&\n typeof payload.code === 'string' &&\n typeof payload.message === 'string'\n ) {\n throw createErrorFromResponse({\n code: payload.code as ErrorCode,\n message: payload.message,\n context: payload.context ?? {},\n httpStatus: getHttpStatus(payload.code as ErrorCode),\n timestamp: new Date().toISOString()\n });\n }\n\n const transportResponse = buildTransportErrorResponse(error);\n const interruptedResponse =\n context.translateTransportErrorsAsInterruptions === false\n ? null\n : buildInterruptedOperationResponse(transportResponse, context);\n throw createErrorFromResponse(\n (interruptedResponse ?? transportResponse) as unknown as ErrorResponse,\n { cause: error }\n );\n }\n\n const wrapped = new Error(String(error));\n throw createErrorFromResponse(\n buildTransportErrorResponse(wrapped) as unknown as ErrorResponse,\n { cause: error }\n );\n}\n\nfunction buildTransportErrorResponse(\n error: Error\n): ErrorResponse<RPCTransportContext> {\n const message = error.message;\n const errorName = error.name;\n let kind: RPCTransportErrorKind = 'unknown';\n let closeCode: number | undefined;\n let closeReason: string | undefined;\n\n if (errorName === 'TypeError') {\n kind = 'invalid_frame';\n } else if (errorName === 'SyntaxError') {\n kind = 'protocol_error';\n } else {\n const peerCloseMatch = message.match(\n /^Peer closed WebSocket: (\\d+) ?(.*)$/\n );\n if (peerCloseMatch) {\n kind = 'peer_closed';\n closeCode = Number(peerCloseMatch[1]);\n closeReason = peerCloseMatch[2] || undefined;\n } else if (message === 'WebSocket connection failed.') {\n kind = 'connection_failed';\n } else if (message.startsWith('WebSocket upgrade failed')) {\n kind = 'upgrade_failed';\n } else if (message === 'No WebSocket in upgrade response') {\n kind = 'upgrade_failed';\n } else if (\n message === 'RPC session was shut down by disposing the main stub' ||\n message === 'RPC was canceled because the RpcPromise was disposed.'\n ) {\n kind = 'session_disposed';\n }\n }\n\n const context: RPCTransportContext = {\n kind,\n originalMessage: message,\n errorName,\n ...(closeCode !== undefined ? { closeCode } : {}),\n ...(closeReason !== undefined ? { closeReason } : {})\n };\n return {\n code: ErrorCode.RPC_TRANSPORT_ERROR,\n message,\n context,\n httpStatus: getHttpStatus(ErrorCode.RPC_TRANSPORT_ERROR),\n suggestion: getSuggestion(\n ErrorCode.RPC_TRANSPORT_ERROR,\n context as unknown as Record<string, unknown>\n ),\n timestamp: new Date().toISOString()\n };\n}\n\nfunction buildInterruptedOperationResponse(\n transportResponse: ErrorResponse<RPCTransportContext>,\n context: RPCTranslationContext\n): ErrorResponse<OperationInterruptedContext> | null {\n if (!context.operation) return null;\n const { kind } = transportResponse.context;\n if (\n kind !== 'session_disposed' &&\n kind !== 'peer_closed' &&\n kind !== 'connection_failed'\n ) {\n return null;\n }\n\n const interruptedContext: OperationInterruptedContext = {\n reason:\n kind === 'session_disposed' ? 'transport_disposed' : 'runtime_replaced',\n operation: context.operation,\n admitted: 'unknown',\n retryable: false\n };\n const action =\n kind === 'session_disposed' ? 'was closing' : 'closed unexpectedly';\n\n return {\n code: ErrorCode.OPERATION_INTERRUPTED,\n message: `Sandbox operation ${context.operation} was interrupted while the runtime connection ${action}`,\n context: interruptedContext,\n httpStatus: getHttpStatus(ErrorCode.OPERATION_INTERRUPTED),\n suggestion: getSuggestion(\n ErrorCode.OPERATION_INTERRUPTED,\n interruptedContext as unknown as Record<string, unknown>\n ),\n timestamp: new Date().toISOString()\n };\n}\n","import { RpcTarget } from 'cloudflare:workers';\nimport { translateRPCError } from '../container-control/rpc-error';\nimport type {\n ProcessPullSubscriptionRPC,\n ProcessSubscriptionRPC\n} from './rpc-types';\n\ninterface RemoteSubscriptionOptions {\n protocol: 'stream' | 'pull';\n signal?: AbortSignal;\n operation?: string;\n abortError?: () => Error;\n}\n\n/** Keeps a stream local to its Durable Object and exposes pull RPC methods. */\nexport class PullSubscriptionTarget<T>\n extends RpcTarget\n implements ProcessPullSubscriptionRPC<T>\n{\n readonly #reader: ReadableStreamDefaultReader<T>;\n readonly #onRelease: (() => void) | undefined;\n #released = false;\n\n constructor(stream: ReadableStream<T>, onRelease?: () => void) {\n super();\n this.#reader = stream.getReader();\n this.#onRelease = onRelease;\n }\n\n async next(): Promise<ReadableStreamReadResult<T>> {\n if (this.#released) return { done: true, value: undefined };\n try {\n const result = await this.#reader.read();\n if (result.done) this.#release();\n return result;\n } catch (error) {\n this.#release();\n throw error;\n }\n }\n\n async cancel(): Promise<void> {\n if (this.#released) return;\n try {\n await this.#reader.cancel();\n } finally {\n this.#release();\n }\n }\n\n [Symbol.dispose](): void {\n if (this.#released) return;\n void this.#reader.cancel().catch(() => undefined);\n this.#release();\n }\n\n #release(): void {\n if (this.#released) return;\n this.#released = true;\n this.#onRelease?.();\n }\n}\n\n/** Exposes a remote Workers RPC subscription as a caller-owned local stream. */\nexport async function openRemoteSubscription<T>(\n subscriptionPromise: Promise<\n ProcessSubscriptionRPC<T> | ProcessPullSubscriptionRPC<T>\n >,\n options: RemoteSubscriptionOptions\n): Promise<ReadableStream<T>> {\n let subscription:\n | ProcessSubscriptionRPC<T>\n | ProcessPullSubscriptionRPC<T>\n | undefined;\n let releaseRequested = false;\n let cleanupStarted = false;\n const release = (): void => {\n releaseRequested = true;\n if (cleanupStarted || subscription === undefined) return;\n cleanupStarted = true;\n try {\n void subscription.cancel().catch(() => undefined);\n } catch {\n // Local disposal still runs after a synchronous RPC failure.\n }\n try {\n subscription[Symbol.dispose]();\n } catch {\n // Cleanup must not replace the consumer's result.\n }\n };\n\n const signal = options.signal;\n const aborted = (): Error =>\n options.abortError?.() ??\n (signal?.reason instanceof Error\n ? signal.reason\n : new Error('Operation aborted'));\n const raceSetup = async <U>(setup: Promise<U>): Promise<U> => {\n if (signal === undefined) return setup;\n if (signal.aborted) {\n release();\n throw aborted();\n }\n let onAbort: (() => void) | undefined;\n const abort = new Promise<never>((_, reject) => {\n onAbort = () => {\n release();\n reject(aborted());\n };\n signal.addEventListener('abort', onAbort, { once: true });\n });\n try {\n return await Promise.race([setup, abort]);\n } finally {\n if (onAbort !== undefined) signal.removeEventListener('abort', onAbort);\n }\n };\n\n try {\n subscription = await raceSetup(\n subscriptionPromise.then((value) => {\n subscription = value;\n if (releaseRequested) release();\n return value;\n })\n );\n } catch (error) {\n if (signal?.aborted) throw error;\n translateRPCError(error, {\n operation: options.operation ?? 'open process subscription'\n });\n }\n\n if (subscription === undefined)\n throw new Error('Process subscription acquisition did not complete');\n\n let read: () => Promise<ReadableStreamReadResult<T>>;\n let cancelReader: () => void;\n if (options.protocol === 'pull') {\n const pullSubscription = subscription as ProcessPullSubscriptionRPC<T>;\n read = () => pullSubscription.next();\n cancelReader = () => undefined;\n } else {\n const streamSubscription = subscription as ProcessSubscriptionRPC<T>;\n let source: ReadableStream<T>;\n try {\n source = await raceSetup(streamSubscription.stream());\n } catch (error) {\n release();\n if (signal?.aborted) throw error;\n translateRPCError(error, {\n operation: options.operation ?? 'open process subscription'\n });\n }\n\n let reader: ReadableStreamDefaultReader<T>;\n try {\n reader = source.getReader();\n } catch (error) {\n release();\n translateRPCError(error, {\n operation: options.operation ?? 'read process subscription'\n });\n }\n read = () => reader.read();\n cancelReader = () => {\n try {\n void reader.cancel().catch(() => undefined);\n } catch {\n // Remote subscription release below remains authoritative.\n }\n };\n }\n\n let stopped = false;\n let controller: ReadableStreamDefaultController<T> | undefined;\n const stop = (error?: Error): void => {\n if (stopped) return;\n stopped = true;\n signal?.removeEventListener('abort', onAbort);\n cancelReader();\n release();\n if (error !== undefined) controller?.error(error);\n };\n const onAbort = (): void => stop(aborted());\n\n return new ReadableStream<T>({\n start(localController) {\n controller = localController;\n if (signal?.aborted) onAbort();\n else signal?.addEventListener('abort', onAbort, { once: true });\n },\n async pull(localController) {\n if (stopped) return;\n try {\n const result = await read();\n if (stopped) return;\n if (result.done) {\n stopped = true;\n signal?.removeEventListener('abort', onAbort);\n release();\n localController.close();\n return;\n }\n localController.enqueue(result.value);\n } catch (error) {\n stop();\n translateRPCError(error, {\n operation: options.operation ?? 'consume process subscription'\n });\n }\n },\n cancel() {\n stop();\n }\n });\n}\n","import { ErrorCode } from '@repo/shared/errors';\nimport { translateRPCError } from '../container-control/rpc-error';\nimport {\n ProcessAbortedError,\n ProcessError,\n ProcessReadyTimeoutError,\n ProcessWaitTimeoutError\n} from '../errors';\n\nexport type WaitOperation = 'output' | 'waitForExit' | 'waitForLog';\n\nexport async function withLocalWait<T>(\n work: (settlementSignal: AbortSignal) => Promise<T>,\n options: {\n processId: string;\n operation: WaitOperation | 'waitForPort' | 'logs';\n timeout?: number;\n signal?: AbortSignal;\n port?: number;\n }\n): Promise<T> {\n const { signal, timeout } = options;\n const settlement = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n let abortListener: (() => void) | undefined;\n const competitors: Promise<T>[] = [work(settlement.signal)];\n\n if (timeout !== undefined) {\n competitors.push(\n new Promise<T>((_, reject) => {\n timer = setTimeout(\n () => reject(timeoutError(options, timeout)),\n timeout\n );\n })\n );\n }\n if (signal !== undefined) {\n competitors.push(\n new Promise<T>((_, reject) => {\n const abort = () =>\n reject(abortError(options.processId, options.operation, signal));\n if (signal.aborted) abort();\n else {\n abortListener = abort;\n signal.addEventListener('abort', abort, { once: true });\n }\n })\n );\n }\n\n try {\n return await Promise.race(competitors);\n } finally {\n settlement.abort();\n if (timer !== undefined) clearTimeout(timer);\n if (abortListener !== undefined)\n signal?.removeEventListener('abort', abortListener);\n }\n}\n\nexport function processFailure(\n processId: string,\n pid: number,\n failure: { code: string; message: string }\n): ProcessError {\n return new ProcessError({\n code: ErrorCode.PROCESS_ERROR,\n message: failure.message,\n context: { processId, pid },\n httpStatus: 500,\n timestamp: new Date().toISOString()\n });\n}\n\nexport function streamClosed(message: string): never {\n translateRPCError(new Error(message), {\n operation: 'consume process subscription',\n translateTransportErrorsAsInterruptions: false\n });\n}\n\nfunction timeoutError(\n options: {\n processId: string;\n operation: WaitOperation | 'waitForPort' | 'logs';\n port?: number;\n },\n timeout: number\n): ProcessWaitTimeoutError | ProcessReadyTimeoutError {\n if (options.operation === 'waitForPort') {\n const condition = `port ${options.port ?? 'unknown'}`;\n return new ProcessReadyTimeoutError({\n code: ErrorCode.PROCESS_READY_TIMEOUT,\n message: `Process did not become ready within ${timeout}ms. Waiting for: ${condition}`,\n context: {\n processId: options.processId,\n command: options.processId,\n condition,\n timeout\n },\n httpStatus: 408,\n timestamp: new Date().toISOString()\n });\n }\n const operation =\n options.operation === 'logs' ? 'waitForLog' : options.operation;\n return new ProcessWaitTimeoutError({\n code: ErrorCode.PROCESS_WAIT_TIMEOUT,\n message: `Process ${operation} did not complete within ${timeout}ms`,\n context: { processId: options.processId, operation, timeout },\n httpStatus: 408,\n timestamp: new Date().toISOString()\n });\n}\n\nexport function abortError(\n processId: string,\n operation: string,\n signal: AbortSignal\n): Error {\n if (signal.reason instanceof Error && signal.reason.name !== 'AbortError')\n return signal.reason;\n return new ProcessAbortedError({\n code: ErrorCode.PROCESS_ABORTED,\n message: `Process ${operation} was aborted`,\n context: { processId, operation },\n httpStatus: 499,\n timestamp: new Date().toISOString()\n });\n}\n","import type { ProcessLogEvent, ProcessOutput } from '@repo/shared';\nimport { processFailure, streamClosed } from './process-waits';\n\nexport async function readProcessOutput(\n reader: ReadableStreamDefaultReader<ProcessLogEvent>,\n options: { maxBytes?: number; processId: string; pid: number }\n): Promise<ProcessOutput<Uint8Array>> {\n const maxBytes = validateMaxBytes(options.maxBytes);\n const stdout: Uint8Array[] = [];\n const stderr: Uint8Array[] = [];\n let stdoutBytes = 0;\n let stderrBytes = 0;\n let retainedBytes = 0;\n let truncated = false;\n\n for (;;) {\n const result = await reader.read();\n if (result.done) streamClosed('Process log stream ended before exit');\n\n const event = result.value;\n if ('type' in event && event.type === 'truncated') {\n truncated = true;\n continue;\n }\n if ('state' in event) {\n if (event.state === 'error')\n throw processFailure(options.processId, options.pid, event.error);\n return {\n stdout: concat(stdout, stdoutBytes),\n stderr: concat(stderr, stderrBytes),\n exitCode: event.exit.code,\n signal: event.exit.signal,\n timedOut: event.exit.timedOut,\n truncated\n };\n }\n\n const remaining =\n maxBytes === undefined\n ? event.data.byteLength\n : Math.max(0, maxBytes - retainedBytes);\n const retainedLength = Math.min(remaining, event.data.byteLength);\n if (retainedLength < event.data.byteLength) truncated = true;\n if (retainedLength === 0) continue;\n\n const chunk =\n retainedLength === event.data.byteLength\n ? event.data\n : event.data.slice(0, retainedLength);\n if (event.type === 'stdout') {\n stdout.push(chunk);\n stdoutBytes += chunk.byteLength;\n } else {\n stderr.push(chunk);\n stderrBytes += chunk.byteLength;\n }\n retainedBytes += chunk.byteLength;\n }\n}\n\nexport function validateMaxBytes(\n maxBytes: number | undefined\n): number | undefined {\n if (maxBytes === undefined) return undefined;\n if (!Number.isFinite(maxBytes) || maxBytes < 0)\n throw new Error('maxBytes must be a non-negative finite number');\n return maxBytes;\n}\n\nfunction concat(chunks: Uint8Array[], length: number): Uint8Array {\n const out = new Uint8Array(length);\n let offset = 0;\n for (const chunk of chunks) {\n out.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return out;\n}\n","import type { PortWatchEvent, ProcessLogEvent } from '@repo/shared';\nimport { ErrorCode } from '@repo/shared/errors';\nimport { ProcessExitedBeforeReadyError } from '../errors';\nimport { processFailure, streamClosed } from './process-waits';\n\nexport async function waitForReadiness(\n portReader: ReadableStreamDefaultReader<PortWatchEvent>,\n logReader: ReadableStreamDefaultReader<ProcessLogEvent>,\n context: { processId: string; pid: number; port: number }\n): Promise<void> {\n await Promise.race([\n consumePort(portReader),\n consumeTerminal(logReader, context)\n ]);\n}\n\nasync function consumePort(\n reader: ReadableStreamDefaultReader<PortWatchEvent>\n): Promise<void> {\n for (;;) {\n const result = await reader.read();\n if (result.done) streamClosed('Port watch stream ended unexpectedly');\n if (result.value.type === 'ready') return;\n if (result.value.type === 'error')\n throw new Error(result.value.error || 'Port watch failed');\n }\n}\n\nasync function consumeTerminal(\n reader: ReadableStreamDefaultReader<ProcessLogEvent>,\n context: { processId: string; pid: number; port: number }\n): Promise<never> {\n for (;;) {\n const result = await reader.read();\n if (result.done) streamClosed('Process log stream ended before exit');\n const event = result.value;\n if (!('state' in event)) continue;\n if (event.state === 'error')\n throw processFailure(context.processId, context.pid, event.error);\n throw exitedBeforeReady(context.processId, context.port, event.exit.code);\n }\n}\n\nfunction exitedBeforeReady(\n processId: string,\n port: number,\n exitCode: number\n): ProcessExitedBeforeReadyError {\n return new ProcessExitedBeforeReadyError({\n code: ErrorCode.PROCESS_EXITED_BEFORE_READY,\n message: `Process exited with code ${exitCode} before becoming ready. Waiting for: port ${port}`,\n context: {\n processId,\n command: processId,\n condition: `port ${port}`,\n exitCode\n },\n httpStatus: 500,\n timestamp: new Date().toISOString()\n });\n}\n","import type { ProcessLogEvent, WaitForLogResult } from '@repo/shared';\nimport { ErrorCode } from '@repo/shared/errors';\nimport { ProcessExitedBeforeLogError } from '../errors';\nimport { processFailure, streamClosed } from './process-waits';\n\nconst MATCH_WINDOW = 64 * 1024;\n\ntype WantedStream = 'stdout' | 'stderr' | 'both';\ntype LogStream = 'stdout' | 'stderr';\n\nexport async function readUntilLogMatch(\n reader: ReadableStreamDefaultReader<ProcessLogEvent>,\n pattern: string | RegExp,\n wanted: WantedStream,\n processId: string,\n pid: number\n): Promise<WaitForLogResult> {\n const decoders = {\n stdout: new TextDecoder(),\n stderr: new TextDecoder()\n };\n const windows = { stdout: '', stderr: '' };\n const cursors = { stdout: '', stderr: '' };\n\n const append = (\n stream: LogStream,\n decoded: string,\n cursor: string\n ): WaitForLogResult | undefined => {\n const text = bounded(windows[stream] + decoded);\n windows[stream] = text;\n cursors[stream] = cursor;\n const match = findMatch(text, pattern);\n return match === undefined ? undefined : { stream, text, match, cursor };\n };\n const flush = (cursor: string): WaitForLogResult | undefined => {\n for (const stream of ['stdout', 'stderr'] as const) {\n if (wanted !== 'both' && wanted !== stream) continue;\n const result = append(\n stream,\n decoders[stream].decode(),\n cursors[stream] || cursor\n );\n if (result !== undefined) return result;\n }\n return undefined;\n };\n\n for (;;) {\n const result = await reader.read();\n if (result.done) {\n const match = flush('');\n if (match !== undefined) return match;\n streamClosed('Process log stream ended before a match was found');\n }\n const event = result.value;\n if ('state' in event) {\n const match = flush(event.cursor);\n if (match !== undefined) return match;\n if (event.state === 'error')\n throw processFailure(processId, pid, event.error);\n throw new ProcessExitedBeforeLogError({\n code: ErrorCode.PROCESS_EXITED_BEFORE_LOG,\n message: 'Process exited before a log match was found',\n context: { processId, pid, exit: { ...event.exit } },\n httpStatus: 409,\n timestamp: new Date().toISOString()\n });\n }\n if (event.type !== 'stdout' && event.type !== 'stderr') continue;\n if (wanted !== 'both' && wanted !== event.type) continue;\n\n const match = append(\n event.type,\n decoders[event.type].decode(event.data, { stream: true }),\n event.cursor\n );\n if (match !== undefined) return match;\n }\n}\n\nfunction bounded(text: string): string {\n return text.length <= MATCH_WINDOW ? text : text.slice(-MATCH_WINDOW);\n}\n\nfunction findMatch(text: string, pattern: string | RegExp): string | undefined {\n if (typeof pattern === 'string')\n return text.includes(pattern) ? pattern : undefined;\n pattern.lastIndex = 0;\n const match = pattern.exec(text)?.[0];\n pattern.lastIndex = 0;\n return match;\n}\n","import type {\n PortWatchEvent,\n ProcessExit,\n ProcessLogEvent,\n ProcessLogsOptions,\n ProcessOutput,\n ProcessOutputOptions,\n ProcessStatus,\n ProcessTextOutputOptions,\n SandboxProcess,\n WaitForLogOptions,\n WaitForLogResult,\n WaitForPortOptions\n} from '@repo/shared';\nimport { readProcessOutput, validateMaxBytes } from './process-output';\nimport { waitForReadiness } from './process-readiness';\nimport {\n abortError,\n processFailure,\n streamClosed,\n withLocalWait\n} from './process-waits';\nimport { openRemoteSubscription } from './remote-subscription';\nimport type { ProcessRPCDescriptor } from './rpc-types';\nimport { readUntilLogMatch } from './wait-for-log';\n\nexport type { SandboxProcess };\n\nexport class SandboxProcessImpl implements SandboxProcess {\n #exitCodePromise?: Promise<number>;\n\n constructor(\n readonly id: string,\n readonly pid: number,\n private readonly capability: ProcessRPCDescriptor['capability']\n ) {}\n\n get exitCode(): Promise<number> {\n this.#exitCodePromise ??= this.waitForExit().then((exit) => exit.code);\n return this.#exitCodePromise;\n }\n\n status(): Promise<ProcessStatus> {\n return this.capability.status();\n }\n\n async logs(\n options: ProcessLogsOptions = {}\n ): Promise<ReadableStream<ProcessLogEvent>> {\n const { signal, ...rpcOptions } = options;\n return openRemoteSubscription(this.capability.openLogs(rpcOptions), {\n protocol: 'pull',\n signal,\n operation: 'read process logs',\n abortError:\n signal === undefined\n ? undefined\n : () => abortError(this.id, 'logs', signal)\n });\n }\n\n output(options: ProcessTextOutputOptions): Promise<ProcessOutput<string>>;\n output(options?: ProcessOutputOptions): Promise<ProcessOutput<Uint8Array>>;\n async output(\n options: ProcessOutputOptions | ProcessTextOutputOptions = {}\n ): Promise<ProcessOutput<Uint8Array> | ProcessOutput<string>> {\n const maxBytes = validateMaxBytes(options.maxBytes);\n const bytes = await withLocalWait(\n (settlementSignal) =>\n this.consumeLogs(settlementSignal, (reader) =>\n readProcessOutput(reader, {\n maxBytes,\n processId: this.id,\n pid: this.pid\n })\n ),\n {\n processId: this.id,\n operation: 'output',\n timeout: options.timeout,\n signal: options.signal\n }\n );\n if ('encoding' in options && options.encoding === 'utf8') {\n return {\n ...bytes,\n stdout: new TextDecoder().decode(bytes.stdout),\n stderr: new TextDecoder().decode(bytes.stderr)\n };\n }\n return bytes;\n }\n\n async waitForExit(\n options: { timeout?: number; signal?: AbortSignal } = {}\n ): Promise<ProcessExit> {\n return withLocalWait(\n (settlementSignal) =>\n this.consumeLogs(settlementSignal, (reader) =>\n readTerminal(reader, this.id, this.pid)\n ),\n {\n processId: this.id,\n operation: 'waitForExit',\n timeout: options.timeout,\n signal: options.signal\n }\n );\n }\n\n async waitForLog(\n pattern: string | RegExp,\n options: WaitForLogOptions = {}\n ): Promise<WaitForLogResult> {\n return withLocalWait(\n (settlementSignal) =>\n this.consumeLogs(settlementSignal, (reader) =>\n readUntilLogMatch(\n reader,\n pattern,\n options.stream ?? 'both',\n this.id,\n this.pid\n )\n ),\n {\n processId: this.id,\n operation: 'waitForLog',\n timeout: options.timeout,\n signal: options.signal\n }\n );\n }\n\n async waitForPort(\n port: number,\n options: WaitForPortOptions = {}\n ): Promise<void> {\n const { timeout, signal, ...rpcOptions } = options;\n return withLocalWait(\n (settlementSignal) =>\n this.waitForPortSubscriptions(port, rpcOptions, settlementSignal),\n {\n processId: this.id,\n operation: 'waitForPort',\n timeout,\n signal,\n port\n }\n );\n }\n\n private async waitForPortSubscriptions(\n port: number,\n options: Omit<WaitForPortOptions, 'timeout' | 'signal'>,\n settlementSignal: AbortSignal\n ): Promise<void> {\n const portStream = await openRemoteSubscription(\n this.capability.openPortWatch(port, options),\n {\n operation: `watch port ${port}`,\n protocol: 'pull',\n signal: settlementSignal\n }\n );\n let logStream: ReadableStream<ProcessLogEvent> | undefined;\n let portReader: ReadableStreamDefaultReader<PortWatchEvent> | undefined;\n let logReader: ReadableStreamDefaultReader<ProcessLogEvent> | undefined;\n try {\n portReader = portStream.getReader();\n logStream = await openRemoteSubscription(\n this.capability.openLogs({ replay: true, follow: true }),\n {\n operation: 'read process logs',\n protocol: 'pull',\n signal: settlementSignal\n }\n );\n logReader = logStream.getReader();\n await waitForReadiness(portReader, logReader, {\n processId: this.id,\n pid: this.pid,\n port\n });\n } finally {\n await cancelOwned(portReader, portStream);\n if (logStream !== undefined) await cancelOwned(logReader, logStream);\n }\n }\n\n kill(signal = 15): Promise<void> {\n return this.capability.kill(signal);\n }\n\n private async consumeLogs<T>(\n signal: AbortSignal,\n consume: (\n reader: ReadableStreamDefaultReader<ProcessLogEvent>\n ) => Promise<T>\n ): Promise<T> {\n const stream = await openRemoteSubscription(\n this.capability.openLogs({ replay: true, follow: true }),\n { signal, operation: 'read process logs', protocol: 'pull' }\n );\n return this.consume(stream, consume);\n }\n\n private async consume<T>(\n stream: ReadableStream<ProcessLogEvent>,\n consume: (\n reader: ReadableStreamDefaultReader<ProcessLogEvent>\n ) => Promise<T>\n ): Promise<T> {\n let reader: ReadableStreamDefaultReader<ProcessLogEvent> | undefined;\n try {\n reader = stream.getReader();\n return await consume(reader);\n } finally {\n await cancelOwned(reader, stream);\n }\n }\n}\n\nexport function createSandboxProcess(\n descriptor: ProcessRPCDescriptor\n): SandboxProcess {\n return new SandboxProcessImpl(\n descriptor.id,\n descriptor.pid,\n descriptor.capability\n );\n}\n\nasync function readTerminal(\n reader: ReadableStreamDefaultReader<ProcessLogEvent>,\n processId: string,\n pid: number\n): Promise<ProcessExit> {\n for (;;) {\n const result = await reader.read();\n if (result.done) streamClosed('Process log stream ended before exit');\n if ('state' in result.value) {\n if (result.value.state === 'exited') return result.value.exit;\n throw processFailure(processId, pid, result.value.error);\n }\n }\n}\n\nasync function cancelOwned<T>(\n reader: ReadableStreamDefaultReader<T> | undefined,\n stream: ReadableStream<T>\n): Promise<void> {\n try {\n if (reader !== undefined) await reader.cancel();\n else await stream.cancel();\n } catch {\n // The primary consumer result wins over cleanup failures.\n }\n}\n","/**\n * Unified extension surface for the Cloudflare Sandbox SDK.\n *\n * Every extension \\u2014 whether it just drives existing control sub-APIs or\n * ships its own container sidecar \\u2014 shares one shape: a class extending\n * {@link SandboxExtension}, captured lazily via a `withX(this)` factory.\n *\n * - No sidecar? Extend {@link SandboxExtension} and use `this.exec()` or\n * `this.withRuntime()` for scoped control APIs. Don't pass a package.\n * - Need a container sidecar? Pass an {@link ExtensionPackage} to `super()`.\n * Then use {@link SandboxExtension.withSidecar} with the sidecar's typed\n * capnweb remote main. Calls on that stub stream through capnweb \\u2014 callback\n * parameters round-trip across both the DO\\u2192container and container\\u2192sidecar\n * hops.\n *\n * `ExtensionPackage` carries tarball bytes produced by an extension build.\n * The SDK sends those bytes only when the container has not provisioned the\n * package hash yet.\n */\n\nimport { RpcTarget } from 'cloudflare:workers';\nimport type {\n ExecOptions,\n ExtensionHealth,\n ExtensionPackage,\n ProcessStatus,\n SandboxBackupAPI,\n SandboxCommand,\n SandboxExtensionsAPI,\n SandboxFilesAPI,\n SandboxPortsAPI,\n SandboxProcess,\n SandboxTerminalsAPI,\n SandboxTunnelsAPI,\n SandboxUtilsAPI,\n SandboxWatchAPI\n} from '@repo/shared';\nimport { EXTENSION_TARBALL_REQUIRED } from '@repo/shared';\nimport { createSandboxProcess } from '../processes';\nimport type { ProcessRPCDescriptor } from '../processes/rpc-types';\n\n// Re-export the wire types so consumers can author extensions from this\n// subpath without reaching into `@repo/shared` directly.\nexport type { ExtensionHealth, ExtensionPackage } from '@repo/shared';\n\nexport type ExtensionRuntimeControl = {\n readonly files: SandboxFilesAPI;\n readonly ports: SandboxPortsAPI;\n readonly backup: SandboxBackupAPI;\n readonly watch: SandboxWatchAPI;\n readonly tunnels: SandboxTunnelsAPI;\n readonly terminals: SandboxTerminalsAPI;\n readonly extensions: SandboxExtensionsAPI;\n readonly utils: SandboxUtilsAPI;\n};\n\ntype ExtensionRuntimeDomain =\n ExtensionRuntimeControl[keyof ExtensionRuntimeControl];\n\nexport type ExtensionRuntimeCallback = (\n control: ExtensionRuntimeControl\n) => Promise<unknown>;\n\ntype ExtensionRuntimeResult<T> = T extends\n | ExtensionRuntimeControl\n | ExtensionRuntimeDomain\n ? never\n : T;\n\nexport type ExtensionRuntimeCallbackResult<\n Call extends ExtensionRuntimeCallback\n> = Awaited<ReturnType<Call>>;\n\ntype RejectEscapingRuntimeCallback<Call extends ExtensionRuntimeCallback> =\n ExtensionRuntimeCallbackResult<Call> extends\n | ExtensionRuntimeControl\n | ExtensionRuntimeDomain\n ? never\n : unknown;\n\nexport type ExtensionRuntimeCall = <Call extends ExtensionRuntimeCallback>(\n operation: string,\n call: Call & RejectEscapingRuntimeCallback<Call>\n) => Promise<ExtensionRuntimeCallbackResult<Call>>;\n\nexport const sandboxRuntimeCall: unique symbol = Symbol('sandboxRuntimeCall');\n\nexport interface HTTPAuthHostConfig {\n token: string;\n username?: string;\n type?: 'basic' | 'bearer';\n}\n\nexport interface HTTPAuthInterceptorParams {\n hosts: Record<string, HTTPAuthHostConfig>;\n}\n\nexport type SandboxLike = {\n readonly [sandboxRuntimeCall]: ExtensionRuntimeCall;\n readonly exec?: (\n command: SandboxCommand,\n options?: ExecOptions\n ) => Promise<SandboxProcess | ProcessRPCDescriptor>;\n readonly getProcess?: (\n processId: string\n ) => Promise<SandboxProcess | ProcessRPCDescriptor | null>;\n readonly listProcesses?: () => Promise<ProcessStatus[]>;\n readonly envVars?: Record<string, string>;\n registerGitAuthInterceptor?: (\n params: HTTPAuthInterceptorParams\n ) => Promise<void>;\n};\n\nexport interface ExtensionProcessSandbox {\n exec(command: SandboxCommand, options?: ExecOptions): Promise<SandboxProcess>;\n getProcess(processId: string): Promise<SandboxProcess | null>;\n listProcesses(): Promise<ProcessStatus[]>;\n}\n\nfunction isProcessRPCDescriptor(\n process: SandboxProcess | ProcessRPCDescriptor\n): process is ProcessRPCDescriptor {\n return 'capability' in process;\n}\n\n/** Normalize local RPC descriptors and caller-side handles for extensions. */\nexport function createExtensionProcessSandbox(\n sandbox: SandboxLike\n): ExtensionProcessSandbox {\n return {\n async exec(command, options) {\n if (!sandbox.exec) {\n throw new Error(\n 'Sandbox extension requires the exec surface from the owning Sandbox'\n );\n }\n const process = await sandbox.exec.call(sandbox, command, options);\n return isProcessRPCDescriptor(process)\n ? createSandboxProcess(process)\n : process;\n },\n async getProcess(processId) {\n if (!sandbox.getProcess) {\n throw new Error(\n 'Sandbox extension requires the getProcess surface from the owning Sandbox'\n );\n }\n const process = await sandbox.getProcess.call(sandbox, processId);\n if (!process) return null;\n return isProcessRPCDescriptor(process)\n ? createSandboxProcess(process)\n : process;\n },\n listProcesses() {\n if (!sandbox.listProcesses) {\n throw new Error(\n 'Sandbox extension requires the listProcesses surface from the owning Sandbox'\n );\n }\n return sandbox.listProcesses.call(sandbox);\n }\n };\n}\n\n/**\n * The one base class for *every* extension.\n *\n * - SDK-only: just drives existing sub-APIs.\n * - Sidecar: pass an {@link ExtensionPackage} to `super(sandbox, pkg)` and\n * call `this.withSidecar<T>(operation, callback)` to use the typed capnweb stub inside one runtime callback.\n *\n * The sidecar helper throws a clear error if no package was supplied, so an\n * extension only \"becomes\" a sidecar extension when it opts in.\n *\n * ```ts\n * // SDK-only\n * class GitStatus extends SandboxExtension {\n * constructor(s: SandboxLike) { super(s); }\n * async status() {\n * const process = await this.exec(['git', 'status']);\n * return process.output({ encoding: 'utf8' });\n * }\n * }\n *\n * // Sidecar\n * import sidecarTarballBytes from './sidecar-package.tgz';\n * import type { MyAPI } from './shared';\n *\n * class MyExt extends SandboxExtension {\n * constructor(s: SandboxLike) { super(s, { tarball: new Uint8Array(sidecarTarballBytes) }); }\n * async run(input: string): Promise<string> {\n * return this.withSidecar<MyAPI, string>('my-ext.run', (api) =>\n * api.run(input)\n * );\n * }\n * }\n * ```\n *\n * RPC-safety: the sandbox lives in `#sandbox` and runtime control is reached\n * only through a symbol-keyed capability, so it is not exposed as a named RPC\n * method. Only the public methods you add form the extension's RPC surface.\n */\nexport abstract class SandboxExtension extends RpcTarget {\n readonly #sandbox: SandboxLike;\n readonly #pkg: ExtensionPackage | undefined;\n #hashPromise: Promise<string> | undefined;\n\n protected constructor(sandbox: SandboxLike, pkg?: ExtensionPackage) {\n super();\n this.#sandbox = sandbox;\n this.#pkg = pkg;\n }\n\n protected withRuntime<Call extends ExtensionRuntimeCallback>(\n operation: string,\n call: Call & RejectEscapingRuntimeCallback<Call>\n ): Promise<ExtensionRuntimeResult<ExtensionRuntimeCallbackResult<Call>>> {\n const guardedCall = async (runtimeControl: ExtensionRuntimeControl) => {\n const { control, revoke } = scopedRuntimeControl(runtimeControl);\n try {\n const result = await call(control);\n assertRuntimeControlDidNotEscape(result, control);\n return result;\n } finally {\n revoke();\n }\n };\n return this.#sandbox[sandboxRuntimeCall](\n operation,\n guardedCall as ExtensionRuntimeCallback\n ) as Promise<ExtensionRuntimeResult<ExtensionRuntimeCallbackResult<Call>>>;\n }\n\n /** Launch an argv process through the owning Sandbox. */\n protected exec(\n command: SandboxCommand,\n options?: ExecOptions\n ): Promise<SandboxProcess> {\n return createExtensionProcessSandbox(this.#sandbox).exec(command, options);\n }\n\n /** Sandbox-level environment applied to extension-launched processes. */\n protected get envVars(): Record<string, string> {\n return this.#sandbox.envVars ?? {};\n }\n\n protected get httpAuthInterceptor():\n | ((params: HTTPAuthInterceptorParams) => Promise<void>)\n | undefined {\n const register = this.#sandbox.registerGitAuthInterceptor;\n return register\n ? (params) => register.call(this.#sandbox, params)\n : undefined;\n }\n\n /**\n * Provision/connect to the sidecar and use its typed capnweb remote inside\n * one runtime callback. The remote is invalid after `call` resolves or\n * rejects, so extension code cannot silently reconnect or keep using an old\n * runtime's sidecar.\n */\n protected async withSidecar<T extends object, Result>(\n operation: string,\n call: (api: T) => Promise<Result>\n ): Promise<Result> {\n const pkg = this.#requirePackage();\n const packageHash = await this.#hashOnce();\n const scopedCall = async (control: ExtensionRuntimeControl) => {\n const connected = await this.#connect<T>(\n control.extensions,\n pkg,\n packageHash\n );\n const { proxy, revoke } = scopedSidecarRemote<T>(connected);\n try {\n const result = await call(proxy);\n assertSidecarRemoteDidNotEscape(result);\n return detachPlainData(result) as Result;\n } finally {\n revoke();\n }\n };\n return (await this.withRuntime(\n operation,\n scopedCall as ExtensionRuntimeCallback\n )) as Result;\n }\n\n /** Health snapshot for this extension's sidecar. */\n protected async sidecarHealth(): Promise<ExtensionHealth> {\n const hash = await this.#hashOnce();\n return await this.withRuntime('extension.health', (control) =>\n control.extensions.health(hash)\n );\n }\n\n /**\n * Stop this extension's sidecar. The next `withSidecar()` call will respawn\n * it on demand.\n */\n protected async stopSidecar(): Promise<void> {\n const hash = await this.#hashOnce();\n await this.withRuntime('extension.stop', (control) =>\n control.extensions.stop(hash)\n );\n }\n\n // --- internals -----------------------------------------------------------\n\n async #connect<T extends object>(\n api: SandboxExtensionsAPI,\n pkg: ExtensionPackage,\n packageHash: string\n ): Promise<T> {\n try {\n return (await api.connect({\n packageHash,\n bin: pkg.bin,\n readinessTimeoutMs: pkg.readinessTimeoutMs,\n allowInstallScripts: pkg.allowInstallScripts\n })) as T;\n } catch (error) {\n if (!isTarballRequiredError(error)) throw error;\n try {\n return (await api.connect({\n packageHash,\n tarball: pkg.tarball,\n bin: pkg.bin,\n readinessTimeoutMs: pkg.readinessTimeoutMs,\n allowInstallScripts: pkg.allowInstallScripts\n })) as T;\n } catch (retryError) {\n throw createSidecarProvisioningError(packageHash, retryError);\n }\n }\n }\n\n #hashOnce(): Promise<string> {\n const pkg = this.#requirePackage();\n this.#hashPromise ??= sha256Hex(pkg.tarball);\n return this.#hashPromise;\n }\n\n #requirePackage(): ExtensionPackage {\n if (!this.#pkg) {\n throw new Error(\n 'This extension has no sidecar package. Pass one to `super(sandbox, pkg)` to use sidecar/sidecarHealth/stopSidecar.'\n );\n }\n return this.#pkg;\n }\n}\n\n/**\n * Recognise the host's `ExtensionTarballRequired` error across the capnweb\n * boundary. There are two cases:\n *\n * 1. capnweb preserves `Error.name`, so the primary wire-safe contract is the\n * string constant `EXTENSION_TARBALL_REQUIRED`.\n * 2. capnweb sometimes re-wraps the error as an `RPCTransportError`, discarding\n * `name` but preserving the message text. We fall back to matching the\n * message so the tarball retry still fires in that case.\n */\nfunction assertRuntimeControlDidNotEscape(\n result: unknown,\n control: ExtensionRuntimeControl\n): void {\n const forbiddenHandles: unknown[] = [\n control,\n control.files,\n control.ports,\n control.backup,\n control.watch,\n control.tunnels,\n control.terminals,\n control.extensions,\n control.utils\n ].filter((handle) => handle !== undefined);\n\n if (!forbiddenHandles.includes(result)) return;\n\n throw new Error(\n 'Sandbox extension runtime callbacks must not return runtime control handles'\n );\n}\n\nfunction scopedRuntimeControl(target: ExtensionRuntimeControl): {\n control: ExtensionRuntimeControl;\n revoke(): void;\n} {\n let active = true;\n const inactiveError = () =>\n new Error(\n 'Sandbox extension runtime control is no longer valid outside its runtime callback'\n );\n const wrappedDomains = new WeakMap<object, object>();\n const scopeDomain = <Domain extends object>(domain: Domain): Domain => {\n const existing = wrappedDomains.get(domain);\n if (existing) return existing as Domain;\n const proxy = new Proxy(domain, {\n get(domainTarget, property, receiver) {\n if (!active) return () => Promise.reject(inactiveError());\n const value = Reflect.get(domainTarget, property, receiver) as unknown;\n if (typeof value === 'function') {\n return (...args: unknown[]) => {\n if (!active) return Promise.reject(inactiveError());\n const result = Reflect.apply(value, domainTarget, args) as unknown;\n return scopeRuntimeResult(result);\n };\n }\n if (typeof value === 'object' && value !== null) {\n if (objectHasCallableMember(value)) return scopeDomain(value);\n return detachPlainData(value);\n }\n return value;\n }\n });\n wrappedDomains.set(domain, proxy);\n return proxy as Domain;\n };\n const scopeRuntimeResult = (result: unknown): unknown => {\n if (result instanceof Promise) {\n return result.then(scopeRuntimeResult);\n }\n if (typeof result === 'object' && result !== null) {\n if (objectHasCallableMember(result)) return scopeDomain(result);\n return detachPlainData(result);\n }\n return result;\n };\n\n const control: ExtensionRuntimeControl = {\n files: scopeDomain(target.files),\n ports: scopeDomain(target.ports),\n backup: scopeDomain(target.backup),\n watch: scopeDomain(target.watch),\n tunnels: scopeDomain(target.tunnels),\n terminals: scopeDomain(target.terminals),\n extensions: scopeDomain(target.extensions),\n utils: scopeDomain(target.utils)\n };\n return {\n control,\n revoke: () => {\n active = false;\n }\n };\n}\n\nconst sidecarRemoteProxies = new WeakSet<object>();\n\nfunction scopedSidecarRemote<T extends object>(\n target: T\n): {\n proxy: T;\n revoke(): void;\n} {\n let active = true;\n const wrappedTargets = new WeakMap<object, object>();\n const createProxy = <Value extends object>(currentTarget: Value): Value => {\n const existing = wrappedTargets.get(currentTarget);\n if (existing) return existing as Value;\n const proxy = new Proxy(currentTarget, {\n get(targetObject, property, receiver) {\n if (!active) {\n return () =>\n Promise.reject(\n new Error(\n 'Sandbox extension sidecar remote is no longer valid outside its runtime callback'\n )\n );\n }\n const value = Reflect.get(targetObject, property, receiver) as unknown;\n if (typeof value === 'function') {\n return (...args: unknown[]) => {\n if (!active) {\n return Promise.reject(\n new Error(\n 'Sandbox extension sidecar remote is no longer valid outside its runtime callback'\n )\n );\n }\n const result = Reflect.apply(value, targetObject, args) as unknown;\n return wrapSidecarResult(result, createProxy);\n };\n }\n if (typeof value === 'object' && value !== null) {\n if (objectHasCallableMember(value)) return createProxy(value);\n return detachPlainData(value);\n }\n return value;\n }\n });\n wrappedTargets.set(currentTarget, proxy);\n sidecarRemoteProxies.add(proxy);\n return proxy as Value;\n };\n\n return {\n proxy: createProxy(target),\n revoke: () => {\n active = false;\n }\n };\n}\n\nfunction wrapSidecarResult(\n result: unknown,\n wrapObject: <Value extends object>(value: Value) => Value\n): unknown {\n if (result instanceof Promise) {\n return result.then((value) => wrapSidecarResult(value, wrapObject));\n }\n if (typeof result === 'object' && result !== null) {\n if (objectHasCallableMember(result)) return wrapObject(result);\n return detachPlainData(result);\n }\n return result;\n}\n\nfunction objectHasCallableMember(value: object): boolean {\n if (Array.isArray(value))\n return value.some((entry) => typeof entry === 'function');\n let current: object | null = value;\n while (current && current !== Object.prototype) {\n for (const property of Reflect.ownKeys(current)) {\n if (property === 'constructor') continue;\n const descriptor = Reflect.getOwnPropertyDescriptor(current, property);\n if (!descriptor) continue;\n if (typeof descriptor.value === 'function') return true;\n if (typeof descriptor.get === 'function') return true;\n }\n current = Reflect.getPrototypeOf(current);\n }\n return false;\n}\n\nfunction assertSidecarRemoteDidNotEscape(result: unknown): void {\n const seen = new WeakSet<object>();\n const visit = (value: unknown): boolean => {\n if (typeof value !== 'object' || value === null) return false;\n if (seen.has(value)) return false;\n seen.add(value);\n if (sidecarRemoteProxies.has(value)) return true;\n if (Array.isArray(value)) return value.some(visit);\n return Object.values(value as Record<string, unknown>).some(visit);\n };\n\n if (!visit(result)) return;\n throw new Error(\n 'Sandbox extension sidecar callbacks must not return sidecar remotes'\n );\n}\n\nfunction detachPlainData<T>(value: T): T {\n if (typeof value !== 'object' || value === null) return value;\n return structuredClone(value) as T;\n}\n\nfunction isTarballRequiredError(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) return false;\n const candidate = error as { name?: unknown; message?: unknown };\n if (candidate.name === EXTENSION_TARBALL_REQUIRED) return true;\n if (typeof candidate.message !== 'string') return false;\n return (\n candidate.message.includes(EXTENSION_TARBALL_REQUIRED) ||\n /Extension package '[0-9a-f]{64}' is not provisioned/.test(\n candidate.message\n )\n );\n}\n\nfunction createSidecarProvisioningError(\n packageHash: string,\n cause: unknown\n): Error {\n const causeMessage =\n cause instanceof Error\n ? cause.message\n : typeof cause === 'string'\n ? cause\n : String(cause);\n return new Error(\n `Failed to provision sandbox sidecar package '${packageHash}'. The sidecar tarball was sent to the container, but the container could not install or start it. Check that the extension build generated a valid npm-style .tgz, that the .tgz is included in the Worker bundle, and that the sidecar package declares a valid package.json bin/sandboxExtension entry. Cause: ${causeMessage}`,\n { cause }\n );\n}\n\n/**\n * Hex sha256 of a tarball via Web Crypto, which is available in workerd and\n * every modern runtime. Avoids a Node-only path so this module stays\n * Worker-bundle-safe.\n */\nasync function sha256Hex(bytes: Uint8Array): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', bytes as BufferSource);\n const view = new Uint8Array(digest);\n let hex = '';\n for (const byte of view) {\n hex += byte.toString(16).padStart(2, '0');\n }\n return hex;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"extensions-Be5HnDGt.js","names":["context","payload: RPCErrorPayload | undefined","kind: RPCTransportErrorKind","closeCode: number | undefined","closeReason: string | undefined","context: RPCTransportContext","interruptedContext: OperationInterruptedContext","#reader","#onRelease","#released","#release","subscription:\n | ProcessSubscriptionRPC<T>\n | ProcessPullSubscriptionRPC<T>\n | undefined","onAbort: (() => void) | undefined","onAbort","read: () => Promise<ReadableStreamReadResult<T>>","cancelReader: () => void","source: ReadableStream<T>","reader: ReadableStreamDefaultReader<T>","controller: ReadableStreamDefaultController<T> | undefined","timer: ReturnType<typeof setTimeout> | undefined","abortListener: (() => void) | undefined","competitors: Promise<T>[]","stdout: Uint8Array[]","stderr: Uint8Array[]","match","id: string","pid: number","capability: ProcessRPCDescriptor['capability']","#exitCodePromise","logStream: ReadableStream<ProcessLogEvent> | undefined","portReader: ReadableStreamDefaultReader<PortWatchEvent> | undefined","logReader: ReadableStreamDefaultReader<ProcessLogEvent> | undefined","reader: ReadableStreamDefaultReader<ProcessLogEvent> | undefined","sandboxRuntimeCall: unique symbol","#sandbox","#pkg","#requirePackage","#hashOnce","#connect","#hashPromise","current: object | null"],"sources":["../src/container-control/rpc-error.ts","../src/processes/remote-subscription.ts","../src/processes/process-waits.ts","../src/processes/process-output.ts","../src/processes/process-readiness.ts","../src/processes/wait-for-log.ts","../src/processes/sandbox-process.ts","../src/extensions/index.ts"],"sourcesContent":["/** Error translation for container control RPC calls. */\n\nimport {\n ErrorCode,\n type ErrorResponse,\n getHttpStatus,\n getSuggestion,\n type OperationInterruptedContext,\n type RPCTransportContext,\n type RPCTransportErrorKind\n} from '@repo/shared/errors';\nimport { createErrorFromResponse } from '../errors/adapter';\nimport { SandboxError } from '../errors/classes';\n\ninterface RPCErrorPayload {\n code: string;\n message: string;\n context?: Record<string, unknown>;\n}\n\nfunction isLocalSandboxError(\n error: Error\n): error is Error & { errorResponse: ErrorResponse } {\n if (!('errorResponse' in error)) return false;\n const response = error.errorResponse as Partial<ErrorResponse> | undefined;\n return (\n typeof response?.code === 'string' &&\n Object.hasOwn(ErrorCode, response.code) &&\n typeof response.message === 'string' &&\n typeof response.httpStatus === 'number' &&\n typeof response.timestamp === 'string' &&\n typeof response.context === 'object' &&\n response.context !== null\n );\n}\n\nexport interface RPCTranslationContext {\n operation?: string;\n translateTransportErrorsAsInterruptions?: boolean;\n}\n\nexport function translateRPCError(\n error: unknown,\n context: RPCTranslationContext = {}\n): never {\n if (error instanceof SandboxError) throw error;\n\n if (error instanceof Error) {\n if (isLocalSandboxError(error)) {\n throw error;\n }\n\n const propagated = error as Error & {\n code?: unknown;\n details?: unknown;\n };\n if (\n typeof propagated.code === 'string' &&\n Object.hasOwn(ErrorCode, propagated.code)\n ) {\n const code = propagated.code as ErrorCode;\n const context =\n propagated.details && typeof propagated.details === 'object'\n ? (propagated.details as Record<string, unknown>)\n : {};\n throw createErrorFromResponse({\n code,\n message: error.message,\n context,\n httpStatus: getHttpStatus(code),\n timestamp: new Date().toISOString()\n });\n }\n\n let payload: RPCErrorPayload | undefined;\n try {\n payload = JSON.parse(error.message) as RPCErrorPayload;\n } catch {}\n if (\n payload &&\n typeof payload.code === 'string' &&\n typeof payload.message === 'string'\n ) {\n throw createErrorFromResponse({\n code: payload.code as ErrorCode,\n message: payload.message,\n context: payload.context ?? {},\n httpStatus: getHttpStatus(payload.code as ErrorCode),\n timestamp: new Date().toISOString()\n });\n }\n\n const transportResponse = buildTransportErrorResponse(error);\n const interruptedResponse =\n context.translateTransportErrorsAsInterruptions === false\n ? null\n : buildInterruptedOperationResponse(transportResponse, context);\n throw createErrorFromResponse(\n (interruptedResponse ?? transportResponse) as unknown as ErrorResponse,\n { cause: error }\n );\n }\n\n const wrapped = new Error(String(error));\n throw createErrorFromResponse(\n buildTransportErrorResponse(wrapped) as unknown as ErrorResponse,\n { cause: error }\n );\n}\n\nfunction buildTransportErrorResponse(\n error: Error\n): ErrorResponse<RPCTransportContext> {\n const message = error.message;\n const errorName = error.name;\n let kind: RPCTransportErrorKind = 'unknown';\n let closeCode: number | undefined;\n let closeReason: string | undefined;\n\n if (errorName === 'TypeError') {\n kind = 'invalid_frame';\n } else if (errorName === 'SyntaxError') {\n kind = 'protocol_error';\n } else {\n const peerCloseMatch = message.match(\n /^Peer closed WebSocket: (\\d+) ?(.*)$/\n );\n if (peerCloseMatch) {\n kind = 'peer_closed';\n closeCode = Number(peerCloseMatch[1]);\n closeReason = peerCloseMatch[2] || undefined;\n } else if (message === 'WebSocket connection failed.') {\n kind = 'connection_failed';\n } else if (message.startsWith('WebSocket upgrade failed')) {\n kind = 'upgrade_failed';\n } else if (message === 'No WebSocket in upgrade response') {\n kind = 'upgrade_failed';\n } else if (\n message === 'RPC session was shut down by disposing the main stub' ||\n message === 'RPC was canceled because the RpcPromise was disposed.'\n ) {\n kind = 'session_disposed';\n }\n }\n\n const context: RPCTransportContext = {\n kind,\n originalMessage: message,\n errorName,\n ...(closeCode !== undefined ? { closeCode } : {}),\n ...(closeReason !== undefined ? { closeReason } : {})\n };\n return {\n code: ErrorCode.RPC_TRANSPORT_ERROR,\n message,\n context,\n httpStatus: getHttpStatus(ErrorCode.RPC_TRANSPORT_ERROR),\n suggestion: getSuggestion(\n ErrorCode.RPC_TRANSPORT_ERROR,\n context as unknown as Record<string, unknown>\n ),\n timestamp: new Date().toISOString()\n };\n}\n\nfunction buildInterruptedOperationResponse(\n transportResponse: ErrorResponse<RPCTransportContext>,\n context: RPCTranslationContext\n): ErrorResponse<OperationInterruptedContext> | null {\n if (!context.operation) return null;\n const { kind } = transportResponse.context;\n if (\n kind !== 'session_disposed' &&\n kind !== 'peer_closed' &&\n kind !== 'connection_failed'\n ) {\n return null;\n }\n\n const interruptedContext: OperationInterruptedContext = {\n reason:\n kind === 'session_disposed' ? 'transport_disposed' : 'runtime_replaced',\n operation: context.operation,\n admitted: 'unknown',\n retryable: false\n };\n const action =\n kind === 'session_disposed' ? 'was closing' : 'closed unexpectedly';\n\n return {\n code: ErrorCode.OPERATION_INTERRUPTED,\n message: `Sandbox operation ${context.operation} was interrupted while the runtime connection ${action}`,\n context: interruptedContext,\n httpStatus: getHttpStatus(ErrorCode.OPERATION_INTERRUPTED),\n suggestion: getSuggestion(\n ErrorCode.OPERATION_INTERRUPTED,\n interruptedContext as unknown as Record<string, unknown>\n ),\n timestamp: new Date().toISOString()\n };\n}\n","import { RpcTarget } from 'cloudflare:workers';\nimport { translateRPCError } from '../container-control/rpc-error';\nimport type {\n ProcessPullSubscriptionRPC,\n ProcessSubscriptionRPC\n} from './rpc-types';\n\ninterface RemoteSubscriptionOptions {\n protocol: 'stream' | 'pull';\n signal?: AbortSignal;\n operation?: string;\n abortError?: () => Error;\n}\n\n/** Keeps a stream local to its Durable Object and exposes pull RPC methods. */\nexport class PullSubscriptionTarget<T>\n extends RpcTarget\n implements ProcessPullSubscriptionRPC<T>\n{\n readonly #reader: ReadableStreamDefaultReader<T>;\n readonly #onRelease: (() => void) | undefined;\n #released = false;\n\n constructor(stream: ReadableStream<T>, onRelease?: () => void) {\n super();\n this.#reader = stream.getReader();\n this.#onRelease = onRelease;\n }\n\n async next(): Promise<ReadableStreamReadResult<T>> {\n if (this.#released) return { done: true, value: undefined };\n try {\n const result = await this.#reader.read();\n if (result.done) this.#release();\n return result;\n } catch (error) {\n this.#release();\n throw error;\n }\n }\n\n async cancel(): Promise<void> {\n if (this.#released) return;\n try {\n await this.#reader.cancel();\n } finally {\n this.#release();\n }\n }\n\n [Symbol.dispose](): void {\n if (this.#released) return;\n void this.#reader.cancel().catch(() => undefined);\n this.#release();\n }\n\n #release(): void {\n if (this.#released) return;\n this.#released = true;\n this.#onRelease?.();\n }\n}\n\n/** Exposes a remote Workers RPC subscription as a caller-owned local stream. */\nexport async function openRemoteSubscription<T>(\n subscriptionPromise: Promise<\n ProcessSubscriptionRPC<T> | ProcessPullSubscriptionRPC<T>\n >,\n options: RemoteSubscriptionOptions\n): Promise<ReadableStream<T>> {\n let subscription:\n | ProcessSubscriptionRPC<T>\n | ProcessPullSubscriptionRPC<T>\n | undefined;\n let releaseRequested = false;\n let cleanupStarted = false;\n const release = (): void => {\n releaseRequested = true;\n if (cleanupStarted || subscription === undefined) return;\n cleanupStarted = true;\n try {\n void subscription.cancel().catch(() => undefined);\n } catch {\n // Local disposal still runs after a synchronous RPC failure.\n }\n try {\n subscription[Symbol.dispose]();\n } catch {\n // Cleanup must not replace the consumer's result.\n }\n };\n\n const signal = options.signal;\n const aborted = (): Error =>\n options.abortError?.() ??\n (signal?.reason instanceof Error\n ? signal.reason\n : new Error('Operation aborted'));\n const raceSetup = async <U>(setup: Promise<U>): Promise<U> => {\n if (signal === undefined) return setup;\n if (signal.aborted) {\n release();\n throw aborted();\n }\n let onAbort: (() => void) | undefined;\n const abort = new Promise<never>((_, reject) => {\n onAbort = () => {\n release();\n reject(aborted());\n };\n signal.addEventListener('abort', onAbort, { once: true });\n });\n try {\n return await Promise.race([setup, abort]);\n } finally {\n if (onAbort !== undefined) signal.removeEventListener('abort', onAbort);\n }\n };\n\n try {\n subscription = await raceSetup(\n subscriptionPromise.then((value) => {\n subscription = value;\n if (releaseRequested) release();\n return value;\n })\n );\n } catch (error) {\n if (signal?.aborted) throw error;\n translateRPCError(error, {\n operation: options.operation ?? 'open process subscription'\n });\n }\n\n if (subscription === undefined)\n throw new Error('Process subscription acquisition did not complete');\n\n let read: () => Promise<ReadableStreamReadResult<T>>;\n let cancelReader: () => void;\n if (options.protocol === 'pull') {\n const pullSubscription = subscription as ProcessPullSubscriptionRPC<T>;\n read = () => pullSubscription.next();\n cancelReader = () => undefined;\n } else {\n const streamSubscription = subscription as ProcessSubscriptionRPC<T>;\n let source: ReadableStream<T>;\n try {\n source = await raceSetup(streamSubscription.stream());\n } catch (error) {\n release();\n if (signal?.aborted) throw error;\n translateRPCError(error, {\n operation: options.operation ?? 'open process subscription'\n });\n }\n\n let reader: ReadableStreamDefaultReader<T>;\n try {\n reader = source.getReader();\n } catch (error) {\n release();\n translateRPCError(error, {\n operation: options.operation ?? 'read process subscription'\n });\n }\n read = () => reader.read();\n cancelReader = () => {\n try {\n void reader.cancel().catch(() => undefined);\n } catch {\n // Remote subscription release below remains authoritative.\n }\n };\n }\n\n let stopped = false;\n let controller: ReadableStreamDefaultController<T> | undefined;\n const stop = (error?: Error): void => {\n if (stopped) return;\n stopped = true;\n signal?.removeEventListener('abort', onAbort);\n cancelReader();\n release();\n if (error !== undefined) controller?.error(error);\n };\n const onAbort = (): void => stop(aborted());\n\n return new ReadableStream<T>({\n start(localController) {\n controller = localController;\n if (signal?.aborted) onAbort();\n else signal?.addEventListener('abort', onAbort, { once: true });\n },\n async pull(localController) {\n if (stopped) return;\n try {\n const result = await read();\n if (stopped) return;\n if (result.done) {\n stopped = true;\n signal?.removeEventListener('abort', onAbort);\n release();\n localController.close();\n return;\n }\n localController.enqueue(result.value);\n } catch (error) {\n stop();\n translateRPCError(error, {\n operation: options.operation ?? 'consume process subscription'\n });\n }\n },\n cancel() {\n stop();\n }\n });\n}\n","import { ErrorCode } from '@repo/shared/errors';\nimport { translateRPCError } from '../container-control/rpc-error';\nimport {\n ProcessAbortedError,\n ProcessError,\n ProcessReadyTimeoutError,\n ProcessWaitTimeoutError\n} from '../errors';\n\nexport type WaitOperation = 'output' | 'waitForExit' | 'waitForLog';\n\nexport async function withLocalWait<T>(\n work: (settlementSignal: AbortSignal) => Promise<T>,\n options: {\n processId: string;\n operation: WaitOperation | 'waitForPort' | 'logs';\n timeout?: number;\n signal?: AbortSignal;\n port?: number;\n }\n): Promise<T> {\n const { signal, timeout } = options;\n const settlement = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n let abortListener: (() => void) | undefined;\n const competitors: Promise<T>[] = [work(settlement.signal)];\n\n if (timeout !== undefined) {\n competitors.push(\n new Promise<T>((_, reject) => {\n timer = setTimeout(\n () => reject(timeoutError(options, timeout)),\n timeout\n );\n })\n );\n }\n if (signal !== undefined) {\n competitors.push(\n new Promise<T>((_, reject) => {\n const abort = () =>\n reject(abortError(options.processId, options.operation, signal));\n if (signal.aborted) abort();\n else {\n abortListener = abort;\n signal.addEventListener('abort', abort, { once: true });\n }\n })\n );\n }\n\n try {\n return await Promise.race(competitors);\n } finally {\n settlement.abort();\n if (timer !== undefined) clearTimeout(timer);\n if (abortListener !== undefined)\n signal?.removeEventListener('abort', abortListener);\n }\n}\n\nexport function processFailure(\n processId: string,\n pid: number,\n failure: { code: string; message: string }\n): ProcessError {\n return new ProcessError({\n code: ErrorCode.PROCESS_ERROR,\n message: failure.message,\n context: { processId, pid },\n httpStatus: 500,\n timestamp: new Date().toISOString()\n });\n}\n\nexport function streamClosed(message: string): never {\n translateRPCError(new Error(message), {\n operation: 'consume process subscription',\n translateTransportErrorsAsInterruptions: false\n });\n}\n\nfunction timeoutError(\n options: {\n processId: string;\n operation: WaitOperation | 'waitForPort' | 'logs';\n port?: number;\n },\n timeout: number\n): ProcessWaitTimeoutError | ProcessReadyTimeoutError {\n if (options.operation === 'waitForPort') {\n const condition = `port ${options.port ?? 'unknown'}`;\n return new ProcessReadyTimeoutError({\n code: ErrorCode.PROCESS_READY_TIMEOUT,\n message: `Process did not become ready within ${timeout}ms. Waiting for: ${condition}`,\n context: {\n processId: options.processId,\n command: options.processId,\n condition,\n timeout\n },\n httpStatus: 408,\n timestamp: new Date().toISOString()\n });\n }\n const operation =\n options.operation === 'logs' ? 'waitForLog' : options.operation;\n return new ProcessWaitTimeoutError({\n code: ErrorCode.PROCESS_WAIT_TIMEOUT,\n message: `Process ${operation} did not complete within ${timeout}ms`,\n context: { processId: options.processId, operation, timeout },\n httpStatus: 408,\n timestamp: new Date().toISOString()\n });\n}\n\nexport function abortError(\n processId: string,\n operation: string,\n signal: AbortSignal\n): Error {\n if (signal.reason instanceof Error && signal.reason.name !== 'AbortError')\n return signal.reason;\n return new ProcessAbortedError({\n code: ErrorCode.PROCESS_ABORTED,\n message: `Process ${operation} was aborted`,\n context: { processId, operation },\n httpStatus: 499,\n timestamp: new Date().toISOString()\n });\n}\n","import type { ProcessLogEvent, ProcessOutput } from '@repo/shared';\nimport { processFailure, streamClosed } from './process-waits';\n\nexport async function readProcessOutput(\n reader: ReadableStreamDefaultReader<ProcessLogEvent>,\n options: { maxBytes?: number; processId: string; pid: number }\n): Promise<ProcessOutput<Uint8Array>> {\n const maxBytes = validateMaxBytes(options.maxBytes);\n const stdout: Uint8Array[] = [];\n const stderr: Uint8Array[] = [];\n let stdoutBytes = 0;\n let stderrBytes = 0;\n let retainedBytes = 0;\n let truncated = false;\n\n for (;;) {\n const result = await reader.read();\n if (result.done) streamClosed('Process log stream ended before exit');\n\n const event = result.value;\n if ('type' in event && event.type === 'truncated') {\n truncated = true;\n continue;\n }\n if ('state' in event) {\n if (event.state === 'error')\n throw processFailure(options.processId, options.pid, event.error);\n return {\n stdout: concat(stdout, stdoutBytes),\n stderr: concat(stderr, stderrBytes),\n exitCode: event.exit.code,\n signal: event.exit.signal,\n timedOut: event.exit.timedOut,\n truncated\n };\n }\n\n const remaining =\n maxBytes === undefined\n ? event.data.byteLength\n : Math.max(0, maxBytes - retainedBytes);\n const retainedLength = Math.min(remaining, event.data.byteLength);\n if (retainedLength < event.data.byteLength) truncated = true;\n if (retainedLength === 0) continue;\n\n const chunk =\n retainedLength === event.data.byteLength\n ? event.data\n : event.data.slice(0, retainedLength);\n if (event.type === 'stdout') {\n stdout.push(chunk);\n stdoutBytes += chunk.byteLength;\n } else {\n stderr.push(chunk);\n stderrBytes += chunk.byteLength;\n }\n retainedBytes += chunk.byteLength;\n }\n}\n\nexport function validateMaxBytes(\n maxBytes: number | undefined\n): number | undefined {\n if (maxBytes === undefined) return undefined;\n if (!Number.isFinite(maxBytes) || maxBytes < 0)\n throw new Error('maxBytes must be a non-negative finite number');\n return maxBytes;\n}\n\nfunction concat(chunks: Uint8Array[], length: number): Uint8Array {\n const out = new Uint8Array(length);\n let offset = 0;\n for (const chunk of chunks) {\n out.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return out;\n}\n","import type { PortWatchEvent, ProcessLogEvent } from '@repo/shared';\nimport { ErrorCode } from '@repo/shared/errors';\nimport { ProcessExitedBeforeReadyError } from '../errors';\nimport { processFailure, streamClosed } from './process-waits';\n\nexport async function waitForReadiness(\n portReader: ReadableStreamDefaultReader<PortWatchEvent>,\n logReader: ReadableStreamDefaultReader<ProcessLogEvent>,\n context: { processId: string; pid: number; port: number }\n): Promise<void> {\n await Promise.race([\n consumePort(portReader),\n consumeTerminal(logReader, context)\n ]);\n}\n\nasync function consumePort(\n reader: ReadableStreamDefaultReader<PortWatchEvent>\n): Promise<void> {\n for (;;) {\n const result = await reader.read();\n if (result.done) streamClosed('Port watch stream ended unexpectedly');\n if (result.value.type === 'ready') return;\n if (result.value.type === 'error')\n throw new Error(result.value.error || 'Port watch failed');\n }\n}\n\nasync function consumeTerminal(\n reader: ReadableStreamDefaultReader<ProcessLogEvent>,\n context: { processId: string; pid: number; port: number }\n): Promise<never> {\n for (;;) {\n const result = await reader.read();\n if (result.done) streamClosed('Process log stream ended before exit');\n const event = result.value;\n if (!('state' in event)) continue;\n if (event.state === 'error')\n throw processFailure(context.processId, context.pid, event.error);\n throw exitedBeforeReady(context.processId, context.port, event.exit.code);\n }\n}\n\nfunction exitedBeforeReady(\n processId: string,\n port: number,\n exitCode: number\n): ProcessExitedBeforeReadyError {\n return new ProcessExitedBeforeReadyError({\n code: ErrorCode.PROCESS_EXITED_BEFORE_READY,\n message: `Process exited with code ${exitCode} before becoming ready. Waiting for: port ${port}`,\n context: {\n processId,\n command: processId,\n condition: `port ${port}`,\n exitCode\n },\n httpStatus: 500,\n timestamp: new Date().toISOString()\n });\n}\n","import type { ProcessLogEvent, WaitForLogResult } from '@repo/shared';\nimport { ErrorCode } from '@repo/shared/errors';\nimport { ProcessExitedBeforeLogError } from '../errors';\nimport { processFailure, streamClosed } from './process-waits';\n\nconst MATCH_WINDOW = 64 * 1024;\n\ntype WantedStream = 'stdout' | 'stderr' | 'both';\ntype LogStream = 'stdout' | 'stderr';\n\nexport async function readUntilLogMatch(\n reader: ReadableStreamDefaultReader<ProcessLogEvent>,\n pattern: string | RegExp,\n wanted: WantedStream,\n processId: string,\n pid: number\n): Promise<WaitForLogResult> {\n const decoders = {\n stdout: new TextDecoder(),\n stderr: new TextDecoder()\n };\n const windows = { stdout: '', stderr: '' };\n const cursors = { stdout: '', stderr: '' };\n\n const append = (\n stream: LogStream,\n decoded: string,\n cursor: string\n ): WaitForLogResult | undefined => {\n const text = bounded(windows[stream] + decoded);\n windows[stream] = text;\n cursors[stream] = cursor;\n const match = findMatch(text, pattern);\n return match === undefined ? undefined : { stream, text, match, cursor };\n };\n const flush = (cursor: string): WaitForLogResult | undefined => {\n for (const stream of ['stdout', 'stderr'] as const) {\n if (wanted !== 'both' && wanted !== stream) continue;\n const result = append(\n stream,\n decoders[stream].decode(),\n cursors[stream] || cursor\n );\n if (result !== undefined) return result;\n }\n return undefined;\n };\n\n for (;;) {\n const result = await reader.read();\n if (result.done) {\n const match = flush('');\n if (match !== undefined) return match;\n streamClosed('Process log stream ended before a match was found');\n }\n const event = result.value;\n if ('state' in event) {\n const match = flush(event.cursor);\n if (match !== undefined) return match;\n if (event.state === 'error')\n throw processFailure(processId, pid, event.error);\n throw new ProcessExitedBeforeLogError({\n code: ErrorCode.PROCESS_EXITED_BEFORE_LOG,\n message: 'Process exited before a log match was found',\n context: { processId, pid, exit: { ...event.exit } },\n httpStatus: 409,\n timestamp: new Date().toISOString()\n });\n }\n if (event.type !== 'stdout' && event.type !== 'stderr') continue;\n if (wanted !== 'both' && wanted !== event.type) continue;\n\n const match = append(\n event.type,\n decoders[event.type].decode(event.data, { stream: true }),\n event.cursor\n );\n if (match !== undefined) return match;\n }\n}\n\nfunction bounded(text: string): string {\n return text.length <= MATCH_WINDOW ? text : text.slice(-MATCH_WINDOW);\n}\n\nfunction findMatch(text: string, pattern: string | RegExp): string | undefined {\n if (typeof pattern === 'string')\n return text.includes(pattern) ? pattern : undefined;\n pattern.lastIndex = 0;\n const match = pattern.exec(text)?.[0];\n pattern.lastIndex = 0;\n return match;\n}\n","import type {\n PortWatchEvent,\n ProcessExit,\n ProcessLogEvent,\n ProcessLogsOptions,\n ProcessOutput,\n ProcessOutputOptions,\n ProcessStatus,\n ProcessTextOutputOptions,\n SandboxProcess,\n WaitForLogOptions,\n WaitForLogResult,\n WaitForPortOptions\n} from '@repo/shared';\nimport { readProcessOutput, validateMaxBytes } from './process-output';\nimport { waitForReadiness } from './process-readiness';\nimport {\n abortError,\n processFailure,\n streamClosed,\n withLocalWait\n} from './process-waits';\nimport { openRemoteSubscription } from './remote-subscription';\nimport type { ProcessRPCDescriptor } from './rpc-types';\nimport { readUntilLogMatch } from './wait-for-log';\n\nexport type { SandboxProcess };\n\nexport class SandboxProcessImpl implements SandboxProcess {\n #exitCodePromise?: Promise<number>;\n\n constructor(\n readonly id: string,\n readonly pid: number,\n private readonly capability: ProcessRPCDescriptor['capability']\n ) {}\n\n get exitCode(): Promise<number> {\n this.#exitCodePromise ??= this.waitForExit().then((exit) => exit.code);\n return this.#exitCodePromise;\n }\n\n status(): Promise<ProcessStatus> {\n return this.capability.status();\n }\n\n async logs(\n options: ProcessLogsOptions = {}\n ): Promise<ReadableStream<ProcessLogEvent>> {\n const { signal, ...rpcOptions } = options;\n return openRemoteSubscription(this.capability.openLogs(rpcOptions), {\n protocol: 'pull',\n signal,\n operation: 'read process logs',\n abortError:\n signal === undefined\n ? undefined\n : () => abortError(this.id, 'logs', signal)\n });\n }\n\n output(options: ProcessTextOutputOptions): Promise<ProcessOutput<string>>;\n output(options?: ProcessOutputOptions): Promise<ProcessOutput<Uint8Array>>;\n async output(\n options: ProcessOutputOptions | ProcessTextOutputOptions = {}\n ): Promise<ProcessOutput<Uint8Array> | ProcessOutput<string>> {\n const maxBytes = validateMaxBytes(options.maxBytes);\n const bytes = await withLocalWait(\n (settlementSignal) =>\n this.consumeLogs(settlementSignal, (reader) =>\n readProcessOutput(reader, {\n maxBytes,\n processId: this.id,\n pid: this.pid\n })\n ),\n {\n processId: this.id,\n operation: 'output',\n timeout: options.timeout,\n signal: options.signal\n }\n );\n if ('encoding' in options && options.encoding === 'utf8') {\n return {\n ...bytes,\n stdout: new TextDecoder().decode(bytes.stdout),\n stderr: new TextDecoder().decode(bytes.stderr)\n };\n }\n return bytes;\n }\n\n async waitForExit(\n options: { timeout?: number; signal?: AbortSignal } = {}\n ): Promise<ProcessExit> {\n return withLocalWait(\n (settlementSignal) =>\n this.consumeLogs(settlementSignal, (reader) =>\n readTerminal(reader, this.id, this.pid)\n ),\n {\n processId: this.id,\n operation: 'waitForExit',\n timeout: options.timeout,\n signal: options.signal\n }\n );\n }\n\n async waitForLog(\n pattern: string | RegExp,\n options: WaitForLogOptions = {}\n ): Promise<WaitForLogResult> {\n return withLocalWait(\n (settlementSignal) =>\n this.consumeLogs(settlementSignal, (reader) =>\n readUntilLogMatch(\n reader,\n pattern,\n options.stream ?? 'both',\n this.id,\n this.pid\n )\n ),\n {\n processId: this.id,\n operation: 'waitForLog',\n timeout: options.timeout,\n signal: options.signal\n }\n );\n }\n\n async waitForPort(\n port: number,\n options: WaitForPortOptions = {}\n ): Promise<void> {\n const { timeout, signal, ...rpcOptions } = options;\n return withLocalWait(\n (settlementSignal) =>\n this.waitForPortSubscriptions(port, rpcOptions, settlementSignal),\n {\n processId: this.id,\n operation: 'waitForPort',\n timeout,\n signal,\n port\n }\n );\n }\n\n private async waitForPortSubscriptions(\n port: number,\n options: Omit<WaitForPortOptions, 'timeout' | 'signal'>,\n settlementSignal: AbortSignal\n ): Promise<void> {\n const portStream = await openRemoteSubscription(\n this.capability.openPortWatch(port, options),\n {\n operation: `watch port ${port}`,\n protocol: 'pull',\n signal: settlementSignal\n }\n );\n let logStream: ReadableStream<ProcessLogEvent> | undefined;\n let portReader: ReadableStreamDefaultReader<PortWatchEvent> | undefined;\n let logReader: ReadableStreamDefaultReader<ProcessLogEvent> | undefined;\n try {\n portReader = portStream.getReader();\n logStream = await openRemoteSubscription(\n this.capability.openLogs({ replay: true, follow: true }),\n {\n operation: 'read process logs',\n protocol: 'pull',\n signal: settlementSignal\n }\n );\n logReader = logStream.getReader();\n await waitForReadiness(portReader, logReader, {\n processId: this.id,\n pid: this.pid,\n port\n });\n } finally {\n await cancelOwned(portReader, portStream);\n if (logStream !== undefined) await cancelOwned(logReader, logStream);\n }\n }\n\n kill(signal = 15): Promise<void> {\n return this.capability.kill(signal);\n }\n\n private async consumeLogs<T>(\n signal: AbortSignal,\n consume: (\n reader: ReadableStreamDefaultReader<ProcessLogEvent>\n ) => Promise<T>\n ): Promise<T> {\n const stream = await openRemoteSubscription(\n this.capability.openLogs({ replay: true, follow: true }),\n { signal, operation: 'read process logs', protocol: 'pull' }\n );\n return this.consume(stream, consume);\n }\n\n private async consume<T>(\n stream: ReadableStream<ProcessLogEvent>,\n consume: (\n reader: ReadableStreamDefaultReader<ProcessLogEvent>\n ) => Promise<T>\n ): Promise<T> {\n let reader: ReadableStreamDefaultReader<ProcessLogEvent> | undefined;\n try {\n reader = stream.getReader();\n return await consume(reader);\n } finally {\n await cancelOwned(reader, stream);\n }\n }\n}\n\nexport function createSandboxProcess(\n descriptor: ProcessRPCDescriptor\n): SandboxProcess {\n return new SandboxProcessImpl(\n descriptor.id,\n descriptor.pid,\n descriptor.capability\n );\n}\n\nasync function readTerminal(\n reader: ReadableStreamDefaultReader<ProcessLogEvent>,\n processId: string,\n pid: number\n): Promise<ProcessExit> {\n for (;;) {\n const result = await reader.read();\n if (result.done) streamClosed('Process log stream ended before exit');\n if ('state' in result.value) {\n if (result.value.state === 'exited') return result.value.exit;\n throw processFailure(processId, pid, result.value.error);\n }\n }\n}\n\nasync function cancelOwned<T>(\n reader: ReadableStreamDefaultReader<T> | undefined,\n stream: ReadableStream<T>\n): Promise<void> {\n try {\n if (reader !== undefined) await reader.cancel();\n else await stream.cancel();\n } catch {\n // The primary consumer result wins over cleanup failures.\n }\n}\n","/**\n * Unified extension surface for the Cloudflare Sandbox SDK.\n *\n * Every extension \\u2014 whether it just drives existing control sub-APIs or\n * ships its own container sidecar \\u2014 shares one shape: a class extending\n * {@link SandboxExtension}, captured lazily via a `withX(this)` factory.\n *\n * - No sidecar? Extend {@link SandboxExtension} and use `this.exec()` or\n * `this.withRuntime()` for scoped control APIs. Don't pass a package.\n * - Need a container sidecar? Pass an {@link ExtensionPackage} to `super()`.\n * Then use {@link SandboxExtension.withSidecar} with the sidecar's typed\n * capnweb remote main. Calls on that stub stream through capnweb \\u2014 callback\n * parameters round-trip across both the DO\\u2192container and container\\u2192sidecar\n * hops.\n *\n * `ExtensionPackage` carries tarball bytes produced by an extension build.\n * The SDK sends those bytes only when the container has not provisioned the\n * package hash yet.\n */\n\nimport { RpcTarget } from 'cloudflare:workers';\nimport type {\n ExecOptions,\n ExtensionHealth,\n ExtensionPackage,\n ProcessStatus,\n SandboxBackupAPI,\n SandboxCommand,\n SandboxExtensionsAPI,\n SandboxFilesAPI,\n SandboxPortsAPI,\n SandboxProcess,\n SandboxTerminalsAPI,\n SandboxTunnelsAPI,\n SandboxUtilsAPI,\n SandboxWatchAPI\n} from '@repo/shared';\nimport { EXTENSION_TARBALL_REQUIRED } from '@repo/shared';\nimport { createSandboxProcess } from '../processes';\nimport type { ProcessRPCDescriptor } from '../processes/rpc-types';\n\n// Re-export the wire types so consumers can author extensions from this\n// subpath without reaching into `@repo/shared` directly.\nexport type { ExtensionHealth, ExtensionPackage } from '@repo/shared';\n\nexport type ExtensionRuntimeControl = {\n readonly files: SandboxFilesAPI;\n readonly ports: SandboxPortsAPI;\n readonly backup: SandboxBackupAPI;\n readonly watch: SandboxWatchAPI;\n readonly tunnels: SandboxTunnelsAPI;\n readonly terminals: SandboxTerminalsAPI;\n readonly extensions: SandboxExtensionsAPI;\n readonly utils: SandboxUtilsAPI;\n};\n\ntype ExtensionRuntimeDomain =\n ExtensionRuntimeControl[keyof ExtensionRuntimeControl];\n\nexport type ExtensionRuntimeCallback = (\n control: ExtensionRuntimeControl\n) => Promise<unknown>;\n\ntype ExtensionRuntimeResult<T> = T extends\n | ExtensionRuntimeControl\n | ExtensionRuntimeDomain\n ? never\n : T;\n\nexport type ExtensionRuntimeCallbackResult<\n Call extends ExtensionRuntimeCallback\n> = Awaited<ReturnType<Call>>;\n\ntype RejectEscapingRuntimeCallback<Call extends ExtensionRuntimeCallback> =\n ExtensionRuntimeCallbackResult<Call> extends\n | ExtensionRuntimeControl\n | ExtensionRuntimeDomain\n ? never\n : unknown;\n\nexport type ExtensionRuntimeCall = <Call extends ExtensionRuntimeCallback>(\n operation: string,\n call: Call & RejectEscapingRuntimeCallback<Call>\n) => Promise<ExtensionRuntimeCallbackResult<Call>>;\n\nexport const sandboxRuntimeCall: unique symbol = Symbol('sandboxRuntimeCall');\n\nexport interface HTTPAuthHostConfig {\n token: string;\n username?: string;\n type?: 'basic' | 'bearer';\n}\n\nexport interface HTTPAuthInterceptorParams {\n hosts: Record<string, HTTPAuthHostConfig>;\n}\n\nexport type SandboxLike = {\n readonly [sandboxRuntimeCall]: ExtensionRuntimeCall;\n readonly exec?: (\n command: SandboxCommand,\n options?: ExecOptions\n ) => Promise<SandboxProcess | ProcessRPCDescriptor>;\n readonly getProcess?: (\n processId: string\n ) => Promise<SandboxProcess | ProcessRPCDescriptor | null>;\n readonly listProcesses?: () => Promise<ProcessStatus[]>;\n readonly envVars?: Record<string, string>;\n registerGitAuthInterceptor?: (\n params: HTTPAuthInterceptorParams\n ) => Promise<void>;\n};\n\nexport interface ExtensionProcessSandbox {\n exec(command: SandboxCommand, options?: ExecOptions): Promise<SandboxProcess>;\n getProcess(processId: string): Promise<SandboxProcess | null>;\n listProcesses(): Promise<ProcessStatus[]>;\n}\n\nfunction isProcessRPCDescriptor(\n process: SandboxProcess | ProcessRPCDescriptor\n): process is ProcessRPCDescriptor {\n return 'capability' in process;\n}\n\n/** Normalize local RPC descriptors and caller-side handles for extensions. */\nexport function createExtensionProcessSandbox(\n sandbox: SandboxLike\n): ExtensionProcessSandbox {\n return {\n async exec(command, options) {\n if (!sandbox.exec) {\n throw new Error(\n 'Sandbox extension requires the exec surface from the owning Sandbox'\n );\n }\n const process = await sandbox.exec.call(sandbox, command, options);\n return isProcessRPCDescriptor(process)\n ? createSandboxProcess(process)\n : process;\n },\n async getProcess(processId) {\n if (!sandbox.getProcess) {\n throw new Error(\n 'Sandbox extension requires the getProcess surface from the owning Sandbox'\n );\n }\n const process = await sandbox.getProcess.call(sandbox, processId);\n if (!process) return null;\n return isProcessRPCDescriptor(process)\n ? createSandboxProcess(process)\n : process;\n },\n listProcesses() {\n if (!sandbox.listProcesses) {\n throw new Error(\n 'Sandbox extension requires the listProcesses surface from the owning Sandbox'\n );\n }\n return sandbox.listProcesses.call(sandbox);\n }\n };\n}\n\n/**\n * The one base class for *every* extension.\n *\n * - SDK-only: just drives existing sub-APIs.\n * - Sidecar: pass an {@link ExtensionPackage} to `super(sandbox, pkg)` and\n * call `this.withSidecar<T>(operation, callback)` to use the typed capnweb stub inside one runtime callback.\n *\n * The sidecar helper throws a clear error if no package was supplied, so an\n * extension only \"becomes\" a sidecar extension when it opts in.\n *\n * ```ts\n * // SDK-only\n * class GitStatus extends SandboxExtension {\n * constructor(s: SandboxLike) { super(s); }\n * async status() {\n * const process = await this.exec(['git', 'status']);\n * return process.output({ encoding: 'utf8' });\n * }\n * }\n *\n * // Sidecar\n * import sidecarTarballBytes from './sidecar-package.tgz';\n * import type { MyAPI } from './shared';\n *\n * class MyExt extends SandboxExtension {\n * constructor(s: SandboxLike) { super(s, { tarball: new Uint8Array(sidecarTarballBytes) }); }\n * async run(input: string): Promise<string> {\n * return this.withSidecar<MyAPI, string>('my-ext.run', (api) =>\n * api.run(input)\n * );\n * }\n * }\n * ```\n *\n * RPC-safety: the sandbox lives in `#sandbox` and runtime control is reached\n * only through a symbol-keyed capability, so it is not exposed as a named RPC\n * method. Only the public methods you add form the extension's RPC surface.\n */\nexport abstract class SandboxExtension extends RpcTarget {\n readonly #sandbox: SandboxLike;\n readonly #pkg: ExtensionPackage | undefined;\n #hashPromise: Promise<string> | undefined;\n\n protected constructor(sandbox: SandboxLike, pkg?: ExtensionPackage) {\n super();\n this.#sandbox = sandbox;\n this.#pkg = pkg;\n }\n\n protected withRuntime<Call extends ExtensionRuntimeCallback>(\n operation: string,\n call: Call & RejectEscapingRuntimeCallback<Call>\n ): Promise<ExtensionRuntimeResult<ExtensionRuntimeCallbackResult<Call>>> {\n const guardedCall = async (runtimeControl: ExtensionRuntimeControl) => {\n const { control, revoke } = scopedRuntimeControl(runtimeControl);\n try {\n const result = await call(control);\n assertRuntimeControlDidNotEscape(result, control);\n return result;\n } finally {\n revoke();\n }\n };\n return this.#sandbox[sandboxRuntimeCall](\n operation,\n guardedCall as ExtensionRuntimeCallback\n ) as Promise<ExtensionRuntimeResult<ExtensionRuntimeCallbackResult<Call>>>;\n }\n\n /** Launch an argv process through the owning Sandbox. */\n protected exec(\n command: SandboxCommand,\n options?: ExecOptions\n ): Promise<SandboxProcess> {\n return createExtensionProcessSandbox(this.#sandbox).exec(command, options);\n }\n\n /** Sandbox-level environment applied to extension-launched processes. */\n protected get envVars(): Record<string, string> {\n return this.#sandbox.envVars ?? {};\n }\n\n protected get httpAuthInterceptor():\n | ((params: HTTPAuthInterceptorParams) => Promise<void>)\n | undefined {\n const register = this.#sandbox.registerGitAuthInterceptor;\n return register\n ? (params) => register.call(this.#sandbox, params)\n : undefined;\n }\n\n /**\n * Provision/connect to the sidecar and use its typed capnweb remote inside\n * one runtime callback. The remote is invalid after `call` resolves or\n * rejects, so extension code cannot silently reconnect or keep using an old\n * runtime's sidecar.\n */\n protected async withSidecar<T extends object, Result>(\n operation: string,\n call: (api: T) => Promise<Result>\n ): Promise<Result> {\n const pkg = this.#requirePackage();\n const packageHash = await this.#hashOnce();\n const scopedCall = async (control: ExtensionRuntimeControl) => {\n const connected = await this.#connect<T>(\n control.extensions,\n pkg,\n packageHash\n );\n const { proxy, revoke } = scopedSidecarRemote<T>(connected);\n try {\n const result = await call(proxy);\n assertSidecarRemoteDidNotEscape(result);\n return detachPlainData(result) as Result;\n } finally {\n revoke();\n }\n };\n return (await this.withRuntime(\n operation,\n scopedCall as ExtensionRuntimeCallback\n )) as Result;\n }\n\n /** Health snapshot for this extension's sidecar. */\n protected async sidecarHealth(): Promise<ExtensionHealth> {\n const hash = await this.#hashOnce();\n return await this.withRuntime('extension.health', (control) =>\n control.extensions.health(hash)\n );\n }\n\n /**\n * Stop this extension's sidecar. The next `withSidecar()` call will respawn\n * it on demand.\n */\n protected async stopSidecar(): Promise<void> {\n const hash = await this.#hashOnce();\n await this.withRuntime('extension.stop', (control) =>\n control.extensions.stop(hash)\n );\n }\n\n // --- internals -----------------------------------------------------------\n\n async #connect<T extends object>(\n api: SandboxExtensionsAPI,\n pkg: ExtensionPackage,\n packageHash: string\n ): Promise<T> {\n try {\n return (await api.connect({\n packageHash,\n bin: pkg.bin,\n readinessTimeoutMs: pkg.readinessTimeoutMs,\n allowInstallScripts: pkg.allowInstallScripts\n })) as T;\n } catch (error) {\n if (!isTarballRequiredError(error)) throw error;\n try {\n return (await api.connect({\n packageHash,\n tarball: pkg.tarball,\n bin: pkg.bin,\n readinessTimeoutMs: pkg.readinessTimeoutMs,\n allowInstallScripts: pkg.allowInstallScripts\n })) as T;\n } catch (retryError) {\n throw createSidecarProvisioningError(packageHash, retryError);\n }\n }\n }\n\n #hashOnce(): Promise<string> {\n const pkg = this.#requirePackage();\n this.#hashPromise ??= sha256Hex(pkg.tarball);\n return this.#hashPromise;\n }\n\n #requirePackage(): ExtensionPackage {\n if (!this.#pkg) {\n throw new Error(\n 'This extension has no sidecar package. Pass one to `super(sandbox, pkg)` to use sidecar/sidecarHealth/stopSidecar.'\n );\n }\n return this.#pkg;\n }\n}\n\n/**\n * Recognise the host's `ExtensionTarballRequired` error across the capnweb\n * boundary. There are two cases:\n *\n * 1. capnweb preserves `Error.name`, so the primary wire-safe contract is the\n * string constant `EXTENSION_TARBALL_REQUIRED`.\n * 2. capnweb sometimes re-wraps the error as an `RPCTransportError`, discarding\n * `name` but preserving the message text. We fall back to matching the\n * message so the tarball retry still fires in that case.\n */\nfunction assertRuntimeControlDidNotEscape(\n result: unknown,\n control: ExtensionRuntimeControl\n): void {\n const forbiddenHandles: unknown[] = [\n control,\n control.files,\n control.ports,\n control.backup,\n control.watch,\n control.tunnels,\n control.terminals,\n control.extensions,\n control.utils\n ].filter((handle) => handle !== undefined);\n\n if (!forbiddenHandles.includes(result)) return;\n\n throw new Error(\n 'Sandbox extension runtime callbacks must not return runtime control handles'\n );\n}\n\nfunction scopedRuntimeControl(target: ExtensionRuntimeControl): {\n control: ExtensionRuntimeControl;\n revoke(): void;\n} {\n let active = true;\n const inactiveError = () =>\n new Error(\n 'Sandbox extension runtime control is no longer valid outside its runtime callback'\n );\n const wrappedDomains = new WeakMap<object, object>();\n const scopeDomain = <Domain extends object>(domain: Domain): Domain => {\n const existing = wrappedDomains.get(domain);\n if (existing) return existing as Domain;\n const proxy = new Proxy(domain, {\n get(domainTarget, property, receiver) {\n if (!active) return () => Promise.reject(inactiveError());\n const value = Reflect.get(domainTarget, property, receiver) as unknown;\n if (typeof value === 'function') {\n return (...args: unknown[]) => {\n if (!active) return Promise.reject(inactiveError());\n const result = Reflect.apply(value, domainTarget, args) as unknown;\n return scopeRuntimeResult(result);\n };\n }\n if (typeof value === 'object' && value !== null) {\n if (objectHasCallableMember(value)) return scopeDomain(value);\n return detachPlainData(value);\n }\n return value;\n }\n });\n wrappedDomains.set(domain, proxy);\n return proxy as Domain;\n };\n const scopeRuntimeResult = (result: unknown): unknown => {\n if (result instanceof Promise) {\n return result.then(scopeRuntimeResult);\n }\n if (typeof result === 'object' && result !== null) {\n if (objectHasCallableMember(result)) return scopeDomain(result);\n return detachPlainData(result);\n }\n return result;\n };\n\n const control: ExtensionRuntimeControl = {\n files: scopeDomain(target.files),\n ports: scopeDomain(target.ports),\n backup: scopeDomain(target.backup),\n watch: scopeDomain(target.watch),\n tunnels: scopeDomain(target.tunnels),\n terminals: scopeDomain(target.terminals),\n extensions: scopeDomain(target.extensions),\n utils: scopeDomain(target.utils)\n };\n return {\n control,\n revoke: () => {\n active = false;\n }\n };\n}\n\nconst sidecarRemoteProxies = new WeakSet<object>();\n\nfunction scopedSidecarRemote<T extends object>(\n target: T\n): {\n proxy: T;\n revoke(): void;\n} {\n let active = true;\n const wrappedTargets = new WeakMap<object, object>();\n const createProxy = <Value extends object>(currentTarget: Value): Value => {\n const existing = wrappedTargets.get(currentTarget);\n if (existing) return existing as Value;\n const proxy = new Proxy(currentTarget, {\n get(targetObject, property, receiver) {\n if (!active) {\n return () =>\n Promise.reject(\n new Error(\n 'Sandbox extension sidecar remote is no longer valid outside its runtime callback'\n )\n );\n }\n const value = Reflect.get(targetObject, property, receiver) as unknown;\n if (typeof value === 'function') {\n return (...args: unknown[]) => {\n if (!active) {\n return Promise.reject(\n new Error(\n 'Sandbox extension sidecar remote is no longer valid outside its runtime callback'\n )\n );\n }\n const result = Reflect.apply(value, targetObject, args) as unknown;\n return wrapSidecarResult(result, createProxy);\n };\n }\n if (typeof value === 'object' && value !== null) {\n if (objectHasCallableMember(value)) return createProxy(value);\n return detachPlainData(value);\n }\n return value;\n }\n });\n wrappedTargets.set(currentTarget, proxy);\n sidecarRemoteProxies.add(proxy);\n return proxy as Value;\n };\n\n return {\n proxy: createProxy(target),\n revoke: () => {\n active = false;\n }\n };\n}\n\nfunction wrapSidecarResult(\n result: unknown,\n wrapObject: <Value extends object>(value: Value) => Value\n): unknown {\n if (result instanceof Promise) {\n return result.then((value) => wrapSidecarResult(value, wrapObject));\n }\n if (typeof result === 'object' && result !== null) {\n if (objectHasCallableMember(result)) return wrapObject(result);\n return detachPlainData(result);\n }\n return result;\n}\n\nfunction objectHasCallableMember(value: object): boolean {\n if (Array.isArray(value))\n return value.some((entry) => typeof entry === 'function');\n let current: object | null = value;\n while (current && current !== Object.prototype) {\n for (const property of Reflect.ownKeys(current)) {\n if (property === 'constructor') continue;\n const descriptor = Reflect.getOwnPropertyDescriptor(current, property);\n if (!descriptor) continue;\n if (typeof descriptor.value === 'function') return true;\n if (typeof descriptor.get === 'function') return true;\n }\n current = Reflect.getPrototypeOf(current);\n }\n return false;\n}\n\nfunction assertSidecarRemoteDidNotEscape(result: unknown): void {\n const seen = new WeakSet<object>();\n const visit = (value: unknown): boolean => {\n if (typeof value !== 'object' || value === null) return false;\n if (seen.has(value)) return false;\n seen.add(value);\n if (sidecarRemoteProxies.has(value)) return true;\n if (Array.isArray(value)) return value.some(visit);\n return Object.values(value as Record<string, unknown>).some(visit);\n };\n\n if (!visit(result)) return;\n throw new Error(\n 'Sandbox extension sidecar callbacks must not return sidecar remotes'\n );\n}\n\nfunction detachPlainData<T>(value: T): T {\n if (typeof value !== 'object' || value === null) return value;\n return structuredClone(value) as T;\n}\n\nfunction isTarballRequiredError(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) return false;\n const candidate = error as { name?: unknown; message?: unknown };\n if (candidate.name === EXTENSION_TARBALL_REQUIRED) return true;\n if (typeof candidate.message !== 'string') return false;\n return (\n candidate.message.includes(EXTENSION_TARBALL_REQUIRED) ||\n /Extension package '[0-9a-f]{64}' is not provisioned/.test(\n candidate.message\n )\n );\n}\n\nfunction createSidecarProvisioningError(\n packageHash: string,\n cause: unknown\n): Error {\n const causeMessage =\n cause instanceof Error\n ? cause.message\n : typeof cause === 'string'\n ? cause\n : String(cause);\n return new Error(\n `Failed to provision sandbox sidecar package '${packageHash}'. The sidecar tarball was sent to the container, but the container could not install or start it. Check that the extension build generated a valid npm-style .tgz, that the .tgz is included in the Worker bundle, and that the sidecar package declares a valid package.json bin/sandboxExtension entry. Cause: ${causeMessage}`,\n { cause }\n );\n}\n\n/**\n * Hex sha256 of a tarball via Web Crypto, which is available in workerd and\n * every modern runtime. Avoids a Node-only path so this module stays\n * Worker-bundle-safe.\n */\nasync function sha256Hex(bytes: Uint8Array): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', bytes as BufferSource);\n const view = new Uint8Array(digest);\n let hex = '';\n for (const byte of view) {\n hex += byte.toString(16).padStart(2, '0');\n }\n return hex;\n}\n"],"mappings":";;;;;;;AAoBA,SAAS,oBACP,OACmD;AACnD,KAAI,EAAE,mBAAmB,OAAQ,QAAO;CACxC,MAAM,WAAW,MAAM;AACvB,QACE,OAAO,UAAU,SAAS,YAC1B,OAAO,OAAO,WAAW,SAAS,KAAK,IACvC,OAAO,SAAS,YAAY,YAC5B,OAAO,SAAS,eAAe,YAC/B,OAAO,SAAS,cAAc,YAC9B,OAAO,SAAS,YAAY,YAC5B,SAAS,YAAY;;AASzB,SAAgB,kBACd,OACA,UAAiC,EAAE,EAC5B;AACP,KAAI,iBAAiB,aAAc,OAAM;AAEzC,KAAI,iBAAiB,OAAO;AAC1B,MAAI,oBAAoB,MAAM,CAC5B,OAAM;EAGR,MAAM,aAAa;AAInB,MACE,OAAO,WAAW,SAAS,YAC3B,OAAO,OAAO,WAAW,WAAW,KAAK,EACzC;GACA,MAAM,OAAO,WAAW;GACxB,MAAMA,YACJ,WAAW,WAAW,OAAO,WAAW,YAAY,WAC/C,WAAW,UACZ,EAAE;AACR,SAAM,wBAAwB;IAC5B;IACA,SAAS,MAAM;IACf;IACA,YAAY,cAAc,KAAK;IAC/B,4BAAW,IAAI,MAAM,EAAC,aAAa;IACpC,CAAC;;EAGJ,IAAIC;AACJ,MAAI;AACF,aAAU,KAAK,MAAM,MAAM,QAAQ;UAC7B;AACR,MACE,WACA,OAAO,QAAQ,SAAS,YACxB,OAAO,QAAQ,YAAY,SAE3B,OAAM,wBAAwB;GAC5B,MAAM,QAAQ;GACd,SAAS,QAAQ;GACjB,SAAS,QAAQ,WAAW,EAAE;GAC9B,YAAY,cAAc,QAAQ,KAAkB;GACpD,4BAAW,IAAI,MAAM,EAAC,aAAa;GACpC,CAAC;EAGJ,MAAM,oBAAoB,4BAA4B,MAAM;AAK5D,QAAM,yBAHJ,QAAQ,4CAA4C,QAChD,OACA,kCAAkC,mBAAmB,QAAQ,KAEzC,mBACxB,EAAE,OAAO,OAAO,CACjB;;AAIH,OAAM,wBACJ,4BAFc,IAAI,MAAM,OAAO,MAAM,CAAC,CAEF,EACpC,EAAE,OAAO,OAAO,CACjB;;AAGH,SAAS,4BACP,OACoC;CACpC,MAAM,UAAU,MAAM;CACtB,MAAM,YAAY,MAAM;CACxB,IAAIC,OAA8B;CAClC,IAAIC;CACJ,IAAIC;AAEJ,KAAI,cAAc,YAChB,QAAO;UACE,cAAc,cACvB,QAAO;MACF;EACL,MAAM,iBAAiB,QAAQ,MAC7B,uCACD;AACD,MAAI,gBAAgB;AAClB,UAAO;AACP,eAAY,OAAO,eAAe,GAAG;AACrC,iBAAc,eAAe,MAAM;aAC1B,YAAY,+BACrB,QAAO;WACE,QAAQ,WAAW,2BAA2B,CACvD,QAAO;WACE,YAAY,mCACrB,QAAO;WAEP,YAAY,0DACZ,YAAY,wDAEZ,QAAO;;CAIX,MAAMC,UAA+B;EACnC;EACA,iBAAiB;EACjB;EACA,GAAI,cAAc,SAAY,EAAE,WAAW,GAAG,EAAE;EAChD,GAAI,gBAAgB,SAAY,EAAE,aAAa,GAAG,EAAE;EACrD;AACD,QAAO;EACL,MAAM,UAAU;EAChB;EACA;EACA,YAAY,cAAc,UAAU,oBAAoB;EACxD,YAAY,cACV,UAAU,qBACV,QACD;EACD,4BAAW,IAAI,MAAM,EAAC,aAAa;EACpC;;AAGH,SAAS,kCACP,mBACA,SACmD;AACnD,KAAI,CAAC,QAAQ,UAAW,QAAO;CAC/B,MAAM,EAAE,SAAS,kBAAkB;AACnC,KACE,SAAS,sBACT,SAAS,iBACT,SAAS,oBAET,QAAO;CAGT,MAAMC,qBAAkD;EACtD,QACE,SAAS,qBAAqB,uBAAuB;EACvD,WAAW,QAAQ;EACnB,UAAU;EACV,WAAW;EACZ;CACD,MAAM,SACJ,SAAS,qBAAqB,gBAAgB;AAEhD,QAAO;EACL,MAAM,UAAU;EAChB,SAAS,qBAAqB,QAAQ,UAAU,gDAAgD;EAChG,SAAS;EACT,YAAY,cAAc,UAAU,sBAAsB;EAC1D,YAAY,cACV,UAAU,uBACV,mBACD;EACD,4BAAW,IAAI,MAAM,EAAC,aAAa;EACpC;;;;;;ACxLH,IAAa,yBAAb,cACU,UAEV;CACE,CAASC;CACT,CAASC;CACT,YAAY;CAEZ,YAAY,QAA2B,WAAwB;AAC7D,SAAO;AACP,QAAKD,SAAU,OAAO,WAAW;AACjC,QAAKC,YAAa;;CAGpB,MAAM,OAA6C;AACjD,MAAI,MAAKC,SAAW,QAAO;GAAE,MAAM;GAAM,OAAO;GAAW;AAC3D,MAAI;GACF,MAAM,SAAS,MAAM,MAAKF,OAAQ,MAAM;AACxC,OAAI,OAAO,KAAM,OAAKG,SAAU;AAChC,UAAO;WACA,OAAO;AACd,SAAKA,SAAU;AACf,SAAM;;;CAIV,MAAM,SAAwB;AAC5B,MAAI,MAAKD,SAAW;AACpB,MAAI;AACF,SAAM,MAAKF,OAAQ,QAAQ;YACnB;AACR,SAAKG,SAAU;;;CAInB,CAAC,OAAO,WAAiB;AACvB,MAAI,MAAKD,SAAW;AACpB,EAAK,MAAKF,OAAQ,QAAQ,CAAC,YAAY,OAAU;AACjD,QAAKG,SAAU;;CAGjB,WAAiB;AACf,MAAI,MAAKD,SAAW;AACpB,QAAKA,WAAY;AACjB,QAAKD,aAAc;;;;AAKvB,eAAsB,uBACpB,qBAGA,SAC4B;CAC5B,IAAIG;CAIJ,IAAI,mBAAmB;CACvB,IAAI,iBAAiB;CACrB,MAAM,gBAAsB;AAC1B,qBAAmB;AACnB,MAAI,kBAAkB,iBAAiB,OAAW;AAClD,mBAAiB;AACjB,MAAI;AACF,GAAK,aAAa,QAAQ,CAAC,YAAY,OAAU;UAC3C;AAGR,MAAI;AACF,gBAAa,OAAO,UAAU;UACxB;;CAKV,MAAM,SAAS,QAAQ;CACvB,MAAM,gBACJ,QAAQ,cAAc,KACrB,QAAQ,kBAAkB,QACvB,OAAO,yBACP,IAAI,MAAM,oBAAoB;CACpC,MAAM,YAAY,OAAU,UAAkC;AAC5D,MAAI,WAAW,OAAW,QAAO;AACjC,MAAI,OAAO,SAAS;AAClB,YAAS;AACT,SAAM,SAAS;;EAEjB,IAAIC;EACJ,MAAM,QAAQ,IAAI,SAAgB,GAAG,WAAW;AAC9C,qBAAgB;AACd,aAAS;AACT,WAAO,SAAS,CAAC;;AAEnB,UAAO,iBAAiB,SAASC,WAAS,EAAE,MAAM,MAAM,CAAC;IACzD;AACF,MAAI;AACF,UAAO,MAAM,QAAQ,KAAK,CAAC,OAAO,MAAM,CAAC;YACjC;AACR,OAAIA,cAAY,OAAW,QAAO,oBAAoB,SAASA,UAAQ;;;AAI3E,KAAI;AACF,iBAAe,MAAM,UACnB,oBAAoB,MAAM,UAAU;AAClC,kBAAe;AACf,OAAI,iBAAkB,UAAS;AAC/B,UAAO;IACP,CACH;UACM,OAAO;AACd,MAAI,QAAQ,QAAS,OAAM;AAC3B,oBAAkB,OAAO,EACvB,WAAW,QAAQ,aAAa,6BACjC,CAAC;;AAGJ,KAAI,iBAAiB,OACnB,OAAM,IAAI,MAAM,oDAAoD;CAEtE,IAAIC;CACJ,IAAIC;AACJ,KAAI,QAAQ,aAAa,QAAQ;EAC/B,MAAM,mBAAmB;AACzB,eAAa,iBAAiB,MAAM;AACpC,uBAAqB;QAChB;EACL,MAAM,qBAAqB;EAC3B,IAAIC;AACJ,MAAI;AACF,YAAS,MAAM,UAAU,mBAAmB,QAAQ,CAAC;WAC9C,OAAO;AACd,YAAS;AACT,OAAI,QAAQ,QAAS,OAAM;AAC3B,qBAAkB,OAAO,EACvB,WAAW,QAAQ,aAAa,6BACjC,CAAC;;EAGJ,IAAIC;AACJ,MAAI;AACF,YAAS,OAAO,WAAW;WACpB,OAAO;AACd,YAAS;AACT,qBAAkB,OAAO,EACvB,WAAW,QAAQ,aAAa,6BACjC,CAAC;;AAEJ,eAAa,OAAO,MAAM;AAC1B,uBAAqB;AACnB,OAAI;AACF,IAAK,OAAO,QAAQ,CAAC,YAAY,OAAU;WACrC;;;CAMZ,IAAI,UAAU;CACd,IAAIC;CACJ,MAAM,QAAQ,UAAwB;AACpC,MAAI,QAAS;AACb,YAAU;AACV,UAAQ,oBAAoB,SAAS,QAAQ;AAC7C,gBAAc;AACd,WAAS;AACT,MAAI,UAAU,OAAW,aAAY,MAAM,MAAM;;CAEnD,MAAM,gBAAsB,KAAK,SAAS,CAAC;AAE3C,QAAO,IAAI,eAAkB;EAC3B,MAAM,iBAAiB;AACrB,gBAAa;AACb,OAAI,QAAQ,QAAS,UAAS;OACzB,SAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,MAAM,CAAC;;EAEjE,MAAM,KAAK,iBAAiB;AAC1B,OAAI,QAAS;AACb,OAAI;IACF,MAAM,SAAS,MAAM,MAAM;AAC3B,QAAI,QAAS;AACb,QAAI,OAAO,MAAM;AACf,eAAU;AACV,aAAQ,oBAAoB,SAAS,QAAQ;AAC7C,cAAS;AACT,qBAAgB,OAAO;AACvB;;AAEF,oBAAgB,QAAQ,OAAO,MAAM;YAC9B,OAAO;AACd,UAAM;AACN,sBAAkB,OAAO,EACvB,WAAW,QAAQ,aAAa,gCACjC,CAAC;;;EAGN,SAAS;AACP,SAAM;;EAET,CAAC;;;;;AC7MJ,eAAsB,cACpB,MACA,SAOY;CACZ,MAAM,EAAE,QAAQ,YAAY;CAC5B,MAAM,aAAa,IAAI,iBAAiB;CACxC,IAAIC;CACJ,IAAIC;CACJ,MAAMC,cAA4B,CAAC,KAAK,WAAW,OAAO,CAAC;AAE3D,KAAI,YAAY,OACd,aAAY,KACV,IAAI,SAAY,GAAG,WAAW;AAC5B,UAAQ,iBACA,OAAO,aAAa,SAAS,QAAQ,CAAC,EAC5C,QACD;GACD,CACH;AAEH,KAAI,WAAW,OACb,aAAY,KACV,IAAI,SAAY,GAAG,WAAW;EAC5B,MAAM,cACJ,OAAO,WAAW,QAAQ,WAAW,QAAQ,WAAW,OAAO,CAAC;AAClE,MAAI,OAAO,QAAS,QAAO;OACtB;AACH,mBAAgB;AAChB,UAAO,iBAAiB,SAAS,OAAO,EAAE,MAAM,MAAM,CAAC;;GAEzD,CACH;AAGH,KAAI;AACF,SAAO,MAAM,QAAQ,KAAK,YAAY;WAC9B;AACR,aAAW,OAAO;AAClB,MAAI,UAAU,OAAW,cAAa,MAAM;AAC5C,MAAI,kBAAkB,OACpB,SAAQ,oBAAoB,SAAS,cAAc;;;AAIzD,SAAgB,eACd,WACA,KACA,SACc;AACd,QAAO,IAAI,aAAa;EACtB,MAAM,UAAU;EAChB,SAAS,QAAQ;EACjB,SAAS;GAAE;GAAW;GAAK;EAC3B,YAAY;EACZ,4BAAW,IAAI,MAAM,EAAC,aAAa;EACpC,CAAC;;AAGJ,SAAgB,aAAa,SAAwB;AACnD,mBAAkB,IAAI,MAAM,QAAQ,EAAE;EACpC,WAAW;EACX,yCAAyC;EAC1C,CAAC;;AAGJ,SAAS,aACP,SAKA,SACoD;AACpD,KAAI,QAAQ,cAAc,eAAe;EACvC,MAAM,YAAY,QAAQ,QAAQ,QAAQ;AAC1C,SAAO,IAAI,yBAAyB;GAClC,MAAM,UAAU;GAChB,SAAS,uCAAuC,QAAQ,mBAAmB;GAC3E,SAAS;IACP,WAAW,QAAQ;IACnB,SAAS,QAAQ;IACjB;IACA;IACD;GACD,YAAY;GACZ,4BAAW,IAAI,MAAM,EAAC,aAAa;GACpC,CAAC;;CAEJ,MAAM,YACJ,QAAQ,cAAc,SAAS,eAAe,QAAQ;AACxD,QAAO,IAAI,wBAAwB;EACjC,MAAM,UAAU;EAChB,SAAS,WAAW,UAAU,2BAA2B,QAAQ;EACjE,SAAS;GAAE,WAAW,QAAQ;GAAW;GAAW;GAAS;EAC7D,YAAY;EACZ,4BAAW,IAAI,MAAM,EAAC,aAAa;EACpC,CAAC;;AAGJ,SAAgB,WACd,WACA,WACA,QACO;AACP,KAAI,OAAO,kBAAkB,SAAS,OAAO,OAAO,SAAS,aAC3D,QAAO,OAAO;AAChB,QAAO,IAAI,oBAAoB;EAC7B,MAAM,UAAU;EAChB,SAAS,WAAW,UAAU;EAC9B,SAAS;GAAE;GAAW;GAAW;EACjC,YAAY;EACZ,4BAAW,IAAI,MAAM,EAAC,aAAa;EACpC,CAAC;;;;;AC9HJ,eAAsB,kBACpB,QACA,SACoC;CACpC,MAAM,WAAW,iBAAiB,QAAQ,SAAS;CACnD,MAAMC,SAAuB,EAAE;CAC/B,MAAMC,SAAuB,EAAE;CAC/B,IAAI,cAAc;CAClB,IAAI,cAAc;CAClB,IAAI,gBAAgB;CACpB,IAAI,YAAY;AAEhB,UAAS;EACP,MAAM,SAAS,MAAM,OAAO,MAAM;AAClC,MAAI,OAAO,KAAM,cAAa,uCAAuC;EAErE,MAAM,QAAQ,OAAO;AACrB,MAAI,UAAU,SAAS,MAAM,SAAS,aAAa;AACjD,eAAY;AACZ;;AAEF,MAAI,WAAW,OAAO;AACpB,OAAI,MAAM,UAAU,QAClB,OAAM,eAAe,QAAQ,WAAW,QAAQ,KAAK,MAAM,MAAM;AACnE,UAAO;IACL,QAAQ,OAAO,QAAQ,YAAY;IACnC,QAAQ,OAAO,QAAQ,YAAY;IACnC,UAAU,MAAM,KAAK;IACrB,QAAQ,MAAM,KAAK;IACnB,UAAU,MAAM,KAAK;IACrB;IACD;;EAGH,MAAM,YACJ,aAAa,SACT,MAAM,KAAK,aACX,KAAK,IAAI,GAAG,WAAW,cAAc;EAC3C,MAAM,iBAAiB,KAAK,IAAI,WAAW,MAAM,KAAK,WAAW;AACjE,MAAI,iBAAiB,MAAM,KAAK,WAAY,aAAY;AACxD,MAAI,mBAAmB,EAAG;EAE1B,MAAM,QACJ,mBAAmB,MAAM,KAAK,aAC1B,MAAM,OACN,MAAM,KAAK,MAAM,GAAG,eAAe;AACzC,MAAI,MAAM,SAAS,UAAU;AAC3B,UAAO,KAAK,MAAM;AAClB,kBAAe,MAAM;SAChB;AACL,UAAO,KAAK,MAAM;AAClB,kBAAe,MAAM;;AAEvB,mBAAiB,MAAM;;;AAI3B,SAAgB,iBACd,UACoB;AACpB,KAAI,aAAa,OAAW,QAAO;AACnC,KAAI,CAAC,OAAO,SAAS,SAAS,IAAI,WAAW,EAC3C,OAAM,IAAI,MAAM,gDAAgD;AAClE,QAAO;;AAGT,SAAS,OAAO,QAAsB,QAA4B;CAChE,MAAM,MAAM,IAAI,WAAW,OAAO;CAClC,IAAI,SAAS;AACb,MAAK,MAAM,SAAS,QAAQ;AAC1B,MAAI,IAAI,OAAO,OAAO;AACtB,YAAU,MAAM;;AAElB,QAAO;;;;;ACvET,eAAsB,iBACpB,YACA,WACA,SACe;AACf,OAAM,QAAQ,KAAK,CACjB,YAAY,WAAW,EACvB,gBAAgB,WAAW,QAAQ,CACpC,CAAC;;AAGJ,eAAe,YACb,QACe;AACf,UAAS;EACP,MAAM,SAAS,MAAM,OAAO,MAAM;AAClC,MAAI,OAAO,KAAM,cAAa,uCAAuC;AACrE,MAAI,OAAO,MAAM,SAAS,QAAS;AACnC,MAAI,OAAO,MAAM,SAAS,QACxB,OAAM,IAAI,MAAM,OAAO,MAAM,SAAS,oBAAoB;;;AAIhE,eAAe,gBACb,QACA,SACgB;AAChB,UAAS;EACP,MAAM,SAAS,MAAM,OAAO,MAAM;AAClC,MAAI,OAAO,KAAM,cAAa,uCAAuC;EACrE,MAAM,QAAQ,OAAO;AACrB,MAAI,EAAE,WAAW,OAAQ;AACzB,MAAI,MAAM,UAAU,QAClB,OAAM,eAAe,QAAQ,WAAW,QAAQ,KAAK,MAAM,MAAM;AACnE,QAAM,kBAAkB,QAAQ,WAAW,QAAQ,MAAM,MAAM,KAAK,KAAK;;;AAI7E,SAAS,kBACP,WACA,MACA,UAC+B;AAC/B,QAAO,IAAI,8BAA8B;EACvC,MAAM,UAAU;EAChB,SAAS,4BAA4B,SAAS,4CAA4C;EAC1F,SAAS;GACP;GACA,SAAS;GACT,WAAW,QAAQ;GACnB;GACD;EACD,YAAY;EACZ,4BAAW,IAAI,MAAM,EAAC,aAAa;EACpC,CAAC;;;;;ACtDJ,MAAM,eAAe,KAAK;AAK1B,eAAsB,kBACpB,QACA,SACA,QACA,WACA,KAC2B;CAC3B,MAAM,WAAW;EACf,QAAQ,IAAI,aAAa;EACzB,QAAQ,IAAI,aAAa;EAC1B;CACD,MAAM,UAAU;EAAE,QAAQ;EAAI,QAAQ;EAAI;CAC1C,MAAM,UAAU;EAAE,QAAQ;EAAI,QAAQ;EAAI;CAE1C,MAAM,UACJ,QACA,SACA,WACiC;EACjC,MAAM,OAAO,QAAQ,QAAQ,UAAU,QAAQ;AAC/C,UAAQ,UAAU;AAClB,UAAQ,UAAU;EAClB,MAAM,QAAQ,UAAU,MAAM,QAAQ;AACtC,SAAO,UAAU,SAAY,SAAY;GAAE;GAAQ;GAAM;GAAO;GAAQ;;CAE1E,MAAM,SAAS,WAAiD;AAC9D,OAAK,MAAM,UAAU,CAAC,UAAU,SAAS,EAAW;AAClD,OAAI,WAAW,UAAU,WAAW,OAAQ;GAC5C,MAAM,SAAS,OACb,QACA,SAAS,QAAQ,QAAQ,EACzB,QAAQ,WAAW,OACpB;AACD,OAAI,WAAW,OAAW,QAAO;;;AAKrC,UAAS;EACP,MAAM,SAAS,MAAM,OAAO,MAAM;AAClC,MAAI,OAAO,MAAM;GACf,MAAMC,UAAQ,MAAM,GAAG;AACvB,OAAIA,YAAU,OAAW,QAAOA;AAChC,gBAAa,oDAAoD;;EAEnE,MAAM,QAAQ,OAAO;AACrB,MAAI,WAAW,OAAO;GACpB,MAAMA,UAAQ,MAAM,MAAM,OAAO;AACjC,OAAIA,YAAU,OAAW,QAAOA;AAChC,OAAI,MAAM,UAAU,QAClB,OAAM,eAAe,WAAW,KAAK,MAAM,MAAM;AACnD,SAAM,IAAI,4BAA4B;IACpC,MAAM,UAAU;IAChB,SAAS;IACT,SAAS;KAAE;KAAW;KAAK,MAAM,EAAE,GAAG,MAAM,MAAM;KAAE;IACpD,YAAY;IACZ,4BAAW,IAAI,MAAM,EAAC,aAAa;IACpC,CAAC;;AAEJ,MAAI,MAAM,SAAS,YAAY,MAAM,SAAS,SAAU;AACxD,MAAI,WAAW,UAAU,WAAW,MAAM,KAAM;EAEhD,MAAM,QAAQ,OACZ,MAAM,MACN,SAAS,MAAM,MAAM,OAAO,MAAM,MAAM,EAAE,QAAQ,MAAM,CAAC,EACzD,MAAM,OACP;AACD,MAAI,UAAU,OAAW,QAAO;;;AAIpC,SAAS,QAAQ,MAAsB;AACrC,QAAO,KAAK,UAAU,eAAe,OAAO,KAAK,MAAM,CAAC,aAAa;;AAGvE,SAAS,UAAU,MAAc,SAA8C;AAC7E,KAAI,OAAO,YAAY,SACrB,QAAO,KAAK,SAAS,QAAQ,GAAG,UAAU;AAC5C,SAAQ,YAAY;CACpB,MAAM,QAAQ,QAAQ,KAAK,KAAK,GAAG;AACnC,SAAQ,YAAY;AACpB,QAAO;;;;;AC/DT,IAAa,qBAAb,MAA0D;CACxD;CAEA,YACE,AAASC,IACT,AAASC,KACT,AAAiBC,YACjB;EAHS;EACA;EACQ;;CAGnB,IAAI,WAA4B;AAC9B,QAAKC,oBAAqB,KAAK,aAAa,CAAC,MAAM,SAAS,KAAK,KAAK;AACtE,SAAO,MAAKA;;CAGd,SAAiC;AAC/B,SAAO,KAAK,WAAW,QAAQ;;CAGjC,MAAM,KACJ,UAA8B,EAAE,EACU;EAC1C,MAAM,EAAE,QAAQ,GAAG,eAAe;AAClC,SAAO,uBAAuB,KAAK,WAAW,SAAS,WAAW,EAAE;GAClE,UAAU;GACV;GACA,WAAW;GACX,YACE,WAAW,SACP,eACM,WAAW,KAAK,IAAI,QAAQ,OAAO;GAChD,CAAC;;CAKJ,MAAM,OACJ,UAA2D,EAAE,EACD;EAC5D,MAAM,WAAW,iBAAiB,QAAQ,SAAS;EACnD,MAAM,QAAQ,MAAM,eACjB,qBACC,KAAK,YAAY,mBAAmB,WAClC,kBAAkB,QAAQ;GACxB;GACA,WAAW,KAAK;GAChB,KAAK,KAAK;GACX,CAAC,CACH,EACH;GACE,WAAW,KAAK;GAChB,WAAW;GACX,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GACjB,CACF;AACD,MAAI,cAAc,WAAW,QAAQ,aAAa,OAChD,QAAO;GACL,GAAG;GACH,QAAQ,IAAI,aAAa,CAAC,OAAO,MAAM,OAAO;GAC9C,QAAQ,IAAI,aAAa,CAAC,OAAO,MAAM,OAAO;GAC/C;AAEH,SAAO;;CAGT,MAAM,YACJ,UAAsD,EAAE,EAClC;AACtB,SAAO,eACJ,qBACC,KAAK,YAAY,mBAAmB,WAClC,aAAa,QAAQ,KAAK,IAAI,KAAK,IAAI,CACxC,EACH;GACE,WAAW,KAAK;GAChB,WAAW;GACX,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GACjB,CACF;;CAGH,MAAM,WACJ,SACA,UAA6B,EAAE,EACJ;AAC3B,SAAO,eACJ,qBACC,KAAK,YAAY,mBAAmB,WAClC,kBACE,QACA,SACA,QAAQ,UAAU,QAClB,KAAK,IACL,KAAK,IACN,CACF,EACH;GACE,WAAW,KAAK;GAChB,WAAW;GACX,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GACjB,CACF;;CAGH,MAAM,YACJ,MACA,UAA8B,EAAE,EACjB;EACf,MAAM,EAAE,SAAS,QAAQ,GAAG,eAAe;AAC3C,SAAO,eACJ,qBACC,KAAK,yBAAyB,MAAM,YAAY,iBAAiB,EACnE;GACE,WAAW,KAAK;GAChB,WAAW;GACX;GACA;GACA;GACD,CACF;;CAGH,MAAc,yBACZ,MACA,SACA,kBACe;EACf,MAAM,aAAa,MAAM,uBACvB,KAAK,WAAW,cAAc,MAAM,QAAQ,EAC5C;GACE,WAAW,cAAc;GACzB,UAAU;GACV,QAAQ;GACT,CACF;EACD,IAAIC;EACJ,IAAIC;EACJ,IAAIC;AACJ,MAAI;AACF,gBAAa,WAAW,WAAW;AACnC,eAAY,MAAM,uBAChB,KAAK,WAAW,SAAS;IAAE,QAAQ;IAAM,QAAQ;IAAM,CAAC,EACxD;IACE,WAAW;IACX,UAAU;IACV,QAAQ;IACT,CACF;AACD,eAAY,UAAU,WAAW;AACjC,SAAM,iBAAiB,YAAY,WAAW;IAC5C,WAAW,KAAK;IAChB,KAAK,KAAK;IACV;IACD,CAAC;YACM;AACR,SAAM,YAAY,YAAY,WAAW;AACzC,OAAI,cAAc,OAAW,OAAM,YAAY,WAAW,UAAU;;;CAIxE,KAAK,SAAS,IAAmB;AAC/B,SAAO,KAAK,WAAW,KAAK,OAAO;;CAGrC,MAAc,YACZ,QACA,SAGY;EACZ,MAAM,SAAS,MAAM,uBACnB,KAAK,WAAW,SAAS;GAAE,QAAQ;GAAM,QAAQ;GAAM,CAAC,EACxD;GAAE;GAAQ,WAAW;GAAqB,UAAU;GAAQ,CAC7D;AACD,SAAO,KAAK,QAAQ,QAAQ,QAAQ;;CAGtC,MAAc,QACZ,QACA,SAGY;EACZ,IAAIC;AACJ,MAAI;AACF,YAAS,OAAO,WAAW;AAC3B,UAAO,MAAM,QAAQ,OAAO;YACpB;AACR,SAAM,YAAY,QAAQ,OAAO;;;;AAKvC,SAAgB,qBACd,YACgB;AAChB,QAAO,IAAI,mBACT,WAAW,IACX,WAAW,KACX,WAAW,WACZ;;AAGH,eAAe,aACb,QACA,WACA,KACsB;AACtB,UAAS;EACP,MAAM,SAAS,MAAM,OAAO,MAAM;AAClC,MAAI,OAAO,KAAM,cAAa,uCAAuC;AACrE,MAAI,WAAW,OAAO,OAAO;AAC3B,OAAI,OAAO,MAAM,UAAU,SAAU,QAAO,OAAO,MAAM;AACzD,SAAM,eAAe,WAAW,KAAK,OAAO,MAAM,MAAM;;;;AAK9D,eAAe,YACb,QACA,QACe;AACf,KAAI;AACF,MAAI,WAAW,OAAW,OAAM,OAAO,QAAQ;MAC1C,OAAM,OAAO,QAAQ;SACpB;;;;;;;;;;;;;;;;;;;;;;;;AC1KV,MAAaC,qBAAoC,OAAO,qBAAqB;AAkC7E,SAAS,uBACP,SACiC;AACjC,QAAO,gBAAgB;;;AAIzB,SAAgB,8BACd,SACyB;AACzB,QAAO;EACL,MAAM,KAAK,SAAS,SAAS;AAC3B,OAAI,CAAC,QAAQ,KACX,OAAM,IAAI,MACR,sEACD;GAEH,MAAM,UAAU,MAAM,QAAQ,KAAK,KAAK,SAAS,SAAS,QAAQ;AAClE,UAAO,uBAAuB,QAAQ,GAClC,qBAAqB,QAAQ,GAC7B;;EAEN,MAAM,WAAW,WAAW;AAC1B,OAAI,CAAC,QAAQ,WACX,OAAM,IAAI,MACR,4EACD;GAEH,MAAM,UAAU,MAAM,QAAQ,WAAW,KAAK,SAAS,UAAU;AACjE,OAAI,CAAC,QAAS,QAAO;AACrB,UAAO,uBAAuB,QAAQ,GAClC,qBAAqB,QAAQ,GAC7B;;EAEN,gBAAgB;AACd,OAAI,CAAC,QAAQ,cACX,OAAM,IAAI,MACR,+EACD;AAEH,UAAO,QAAQ,cAAc,KAAK,QAAQ;;EAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCH,IAAsB,mBAAtB,cAA+C,UAAU;CACvD,CAASC;CACT,CAASC;CACT;CAEA,AAAU,YAAY,SAAsB,KAAwB;AAClE,SAAO;AACP,QAAKD,UAAW;AAChB,QAAKC,MAAO;;CAGd,AAAU,YACR,WACA,MACuE;EACvE,MAAM,cAAc,OAAO,mBAA4C;GACrE,MAAM,EAAE,SAAS,WAAW,qBAAqB,eAAe;AAChE,OAAI;IACF,MAAM,SAAS,MAAM,KAAK,QAAQ;AAClC,qCAAiC,QAAQ,QAAQ;AACjD,WAAO;aACC;AACR,YAAQ;;;AAGZ,SAAO,MAAKD,QAAS,oBACnB,WACA,YACD;;;CAIH,AAAU,KACR,SACA,SACyB;AACzB,SAAO,8BAA8B,MAAKA,QAAS,CAAC,KAAK,SAAS,QAAQ;;;CAI5E,IAAc,UAAkC;AAC9C,SAAO,MAAKA,QAAS,WAAW,EAAE;;CAGpC,IAAc,sBAEA;EACZ,MAAM,WAAW,MAAKA,QAAS;AAC/B,SAAO,YACF,WAAW,SAAS,KAAK,MAAKA,SAAU,OAAO,GAChD;;;;;;;;CASN,MAAgB,YACd,WACA,MACiB;EACjB,MAAM,MAAM,MAAKE,gBAAiB;EAClC,MAAM,cAAc,MAAM,MAAKC,UAAW;EAC1C,MAAM,aAAa,OAAO,YAAqC;GAM7D,MAAM,EAAE,OAAO,WAAW,oBALR,MAAM,MAAKC,QAC3B,QAAQ,YACR,KACA,YACD,CAC0D;AAC3D,OAAI;IACF,MAAM,SAAS,MAAM,KAAK,MAAM;AAChC,oCAAgC,OAAO;AACvC,WAAO,gBAAgB,OAAO;aACtB;AACR,YAAQ;;;AAGZ,SAAQ,MAAM,KAAK,YACjB,WACA,WACD;;;CAIH,MAAgB,gBAA0C;EACxD,MAAM,OAAO,MAAM,MAAKD,UAAW;AACnC,SAAO,MAAM,KAAK,YAAY,qBAAqB,YACjD,QAAQ,WAAW,OAAO,KAAK,CAChC;;;;;;CAOH,MAAgB,cAA6B;EAC3C,MAAM,OAAO,MAAM,MAAKA,UAAW;AACnC,QAAM,KAAK,YAAY,mBAAmB,YACxC,QAAQ,WAAW,KAAK,KAAK,CAC9B;;CAKH,OAAMC,QACJ,KACA,KACA,aACY;AACZ,MAAI;AACF,UAAQ,MAAM,IAAI,QAAQ;IACxB;IACA,KAAK,IAAI;IACT,oBAAoB,IAAI;IACxB,qBAAqB,IAAI;IAC1B,CAAC;WACK,OAAO;AACd,OAAI,CAAC,uBAAuB,MAAM,CAAE,OAAM;AAC1C,OAAI;AACF,WAAQ,MAAM,IAAI,QAAQ;KACxB;KACA,SAAS,IAAI;KACb,KAAK,IAAI;KACT,oBAAoB,IAAI;KACxB,qBAAqB,IAAI;KAC1B,CAAC;YACK,YAAY;AACnB,UAAM,+BAA+B,aAAa,WAAW;;;;CAKnE,YAA6B;EAC3B,MAAM,MAAM,MAAKF,gBAAiB;AAClC,QAAKG,gBAAiB,UAAU,IAAI,QAAQ;AAC5C,SAAO,MAAKA;;CAGd,kBAAoC;AAClC,MAAI,CAAC,MAAKJ,IACR,OAAM,IAAI,MACR,qHACD;AAEH,SAAO,MAAKA;;;;;;;;;;;;;AAchB,SAAS,iCACP,QACA,SACM;AAaN,KAAI,CAZgC;EAClC;EACA,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACT,CAAC,QAAQ,WAAW,WAAW,OAAU,CAEpB,SAAS,OAAO,CAAE;AAExC,OAAM,IAAI,MACR,8EACD;;AAGH,SAAS,qBAAqB,QAG5B;CACA,IAAI,SAAS;CACb,MAAM,sCACJ,IAAI,MACF,oFACD;CACH,MAAM,iCAAiB,IAAI,SAAyB;CACpD,MAAM,eAAsC,WAA2B;EACrE,MAAM,WAAW,eAAe,IAAI,OAAO;AAC3C,MAAI,SAAU,QAAO;EACrB,MAAM,QAAQ,IAAI,MAAM,QAAQ,EAC9B,IAAI,cAAc,UAAU,UAAU;AACpC,OAAI,CAAC,OAAQ,cAAa,QAAQ,OAAO,eAAe,CAAC;GACzD,MAAM,QAAQ,QAAQ,IAAI,cAAc,UAAU,SAAS;AAC3D,OAAI,OAAO,UAAU,WACnB,SAAQ,GAAG,SAAoB;AAC7B,QAAI,CAAC,OAAQ,QAAO,QAAQ,OAAO,eAAe,CAAC;AAEnD,WAAO,mBADQ,QAAQ,MAAM,OAAO,cAAc,KAAK,CACtB;;AAGrC,OAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,QAAI,wBAAwB,MAAM,CAAE,QAAO,YAAY,MAAM;AAC7D,WAAO,gBAAgB,MAAM;;AAE/B,UAAO;KAEV,CAAC;AACF,iBAAe,IAAI,QAAQ,MAAM;AACjC,SAAO;;CAET,MAAM,sBAAsB,WAA6B;AACvD,MAAI,kBAAkB,QACpB,QAAO,OAAO,KAAK,mBAAmB;AAExC,MAAI,OAAO,WAAW,YAAY,WAAW,MAAM;AACjD,OAAI,wBAAwB,OAAO,CAAE,QAAO,YAAY,OAAO;AAC/D,UAAO,gBAAgB,OAAO;;AAEhC,SAAO;;AAaT,QAAO;EACL,SAXuC;GACvC,OAAO,YAAY,OAAO,MAAM;GAChC,OAAO,YAAY,OAAO,MAAM;GAChC,QAAQ,YAAY,OAAO,OAAO;GAClC,OAAO,YAAY,OAAO,MAAM;GAChC,SAAS,YAAY,OAAO,QAAQ;GACpC,WAAW,YAAY,OAAO,UAAU;GACxC,YAAY,YAAY,OAAO,WAAW;GAC1C,OAAO,YAAY,OAAO,MAAM;GACjC;EAGC,cAAc;AACZ,YAAS;;EAEZ;;AAGH,MAAM,uCAAuB,IAAI,SAAiB;AAElD,SAAS,oBACP,QAIA;CACA,IAAI,SAAS;CACb,MAAM,iCAAiB,IAAI,SAAyB;CACpD,MAAM,eAAqC,kBAAgC;EACzE,MAAM,WAAW,eAAe,IAAI,cAAc;AAClD,MAAI,SAAU,QAAO;EACrB,MAAM,QAAQ,IAAI,MAAM,eAAe,EACrC,IAAI,cAAc,UAAU,UAAU;AACpC,OAAI,CAAC,OACH,cACE,QAAQ,uBACN,IAAI,MACF,mFACD,CACF;GAEL,MAAM,QAAQ,QAAQ,IAAI,cAAc,UAAU,SAAS;AAC3D,OAAI,OAAO,UAAU,WACnB,SAAQ,GAAG,SAAoB;AAC7B,QAAI,CAAC,OACH,QAAO,QAAQ,uBACb,IAAI,MACF,mFACD,CACF;AAGH,WAAO,kBADQ,QAAQ,MAAM,OAAO,cAAc,KAAK,EACtB,YAAY;;AAGjD,OAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,QAAI,wBAAwB,MAAM,CAAE,QAAO,YAAY,MAAM;AAC7D,WAAO,gBAAgB,MAAM;;AAE/B,UAAO;KAEV,CAAC;AACF,iBAAe,IAAI,eAAe,MAAM;AACxC,uBAAqB,IAAI,MAAM;AAC/B,SAAO;;AAGT,QAAO;EACL,OAAO,YAAY,OAAO;EAC1B,cAAc;AACZ,YAAS;;EAEZ;;AAGH,SAAS,kBACP,QACA,YACS;AACT,KAAI,kBAAkB,QACpB,QAAO,OAAO,MAAM,UAAU,kBAAkB,OAAO,WAAW,CAAC;AAErE,KAAI,OAAO,WAAW,YAAY,WAAW,MAAM;AACjD,MAAI,wBAAwB,OAAO,CAAE,QAAO,WAAW,OAAO;AAC9D,SAAO,gBAAgB,OAAO;;AAEhC,QAAO;;AAGT,SAAS,wBAAwB,OAAwB;AACvD,KAAI,MAAM,QAAQ,MAAM,CACtB,QAAO,MAAM,MAAM,UAAU,OAAO,UAAU,WAAW;CAC3D,IAAIK,UAAyB;AAC7B,QAAO,WAAW,YAAY,OAAO,WAAW;AAC9C,OAAK,MAAM,YAAY,QAAQ,QAAQ,QAAQ,EAAE;AAC/C,OAAI,aAAa,cAAe;GAChC,MAAM,aAAa,QAAQ,yBAAyB,SAAS,SAAS;AACtE,OAAI,CAAC,WAAY;AACjB,OAAI,OAAO,WAAW,UAAU,WAAY,QAAO;AACnD,OAAI,OAAO,WAAW,QAAQ,WAAY,QAAO;;AAEnD,YAAU,QAAQ,eAAe,QAAQ;;AAE3C,QAAO;;AAGT,SAAS,gCAAgC,QAAuB;CAC9D,MAAM,uBAAO,IAAI,SAAiB;CAClC,MAAM,SAAS,UAA4B;AACzC,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,MAAI,KAAK,IAAI,MAAM,CAAE,QAAO;AAC5B,OAAK,IAAI,MAAM;AACf,MAAI,qBAAqB,IAAI,MAAM,CAAE,QAAO;AAC5C,MAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,MAAM,KAAK,MAAM;AAClD,SAAO,OAAO,OAAO,MAAiC,CAAC,KAAK,MAAM;;AAGpE,KAAI,CAAC,MAAM,OAAO,CAAE;AACpB,OAAM,IAAI,MACR,sEACD;;AAGH,SAAS,gBAAmB,OAAa;AACvC,KAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAO,gBAAgB,MAAM;;AAG/B,SAAS,uBAAuB,OAAyB;AACvD,KAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;CACxD,MAAM,YAAY;AAClB,KAAI,UAAU,SAAS,2BAA4B,QAAO;AAC1D,KAAI,OAAO,UAAU,YAAY,SAAU,QAAO;AAClD,QACE,UAAU,QAAQ,SAAS,2BAA2B,IACtD,sDAAsD,KACpD,UAAU,QACX;;AAIL,SAAS,+BACP,aACA,OACO;CACP,MAAM,eACJ,iBAAiB,QACb,MAAM,UACN,OAAO,UAAU,WACf,QACA,OAAO,MAAM;AACrB,QAAO,IAAI,MACT,gDAAgD,YAAY,oTAAoT,gBAChX,EAAE,OAAO,CACV;;;;;;;AAQH,eAAe,UAAU,OAAoC;CAC3D,MAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,MAAsB;CAC3E,MAAM,OAAO,IAAI,WAAW,OAAO;CACnC,IAAI,MAAM;AACV,MAAK,MAAM,QAAQ,KACjB,QAAO,KAAK,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI;AAE3C,QAAO"}
|