dotdo 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +446 -315
- package/cli/README.md +238 -0
- package/cli/agent.ts +72 -0
- package/cli/bin.js +44 -0
- package/cli/bin.ts +38 -0
- package/cli/build.ts +157 -0
- package/cli/commands/auth/login.ts +14 -0
- package/cli/commands/auth/logout.ts +6 -0
- package/cli/commands/auth/whoami.ts +16 -0
- package/cli/commands/deploy-multi.ts +245 -0
- package/cli/commands/dev/deploy.ts +100 -0
- package/cli/commands/dev/dev.ts +95 -0
- package/cli/commands/dev/logs.ts +91 -0
- package/cli/commands/dev-local.ts +88 -0
- package/cli/commands/do-ops.ts +314 -0
- package/cli/commands/index.ts +100 -0
- package/cli/commands/init.ts +247 -0
- package/cli/commands/introspect/emitter.ts +315 -0
- package/cli/commands/introspect/index.ts +193 -0
- package/cli/commands/link.ts +598 -0
- package/cli/commands/snippets.ts +415 -0
- package/cli/commands/tunnel.ts +239 -0
- package/cli/device-auth.ts +289 -0
- package/cli/fallback.ts +12 -0
- package/cli/index.ts +121 -0
- package/cli/main.ts +246 -0
- package/cli/mcp-stdio.ts +790 -0
- package/cli/package.json +62 -0
- package/cli/runtime/do-registry.ts +193 -0
- package/cli/runtime/embedded-db.ts +344 -0
- package/cli/runtime/index.ts +9 -0
- package/cli/runtime/miniflare-adapter.ts +162 -0
- package/cli/sandbox.ts +82 -0
- package/cli/src/args.ts +174 -0
- package/cli/src/auth.ts +55 -0
- package/cli/src/commands/call.ts +84 -0
- package/cli/src/commands/charge.ts +96 -0
- package/cli/src/commands/config.ts +115 -0
- package/cli/src/commands/email.ts +112 -0
- package/cli/src/commands/llm.ts +115 -0
- package/cli/src/commands/queue.ts +134 -0
- package/cli/src/commands/text.ts +86 -0
- package/cli/src/config.ts +185 -0
- package/cli/src/output.ts +246 -0
- package/cli/src/rpc.ts +192 -0
- package/cli/utils/config.ts +282 -0
- package/cli/utils/detect.ts +73 -0
- package/cli/utils/index.ts +15 -0
- package/cli/utils/logger.ts +232 -0
- package/dist/ai/index.js +19 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/template-literals.js +852 -0
- package/dist/ai/template-literals.js.map +1 -0
- package/dist/api/middleware/auth-federation.js +573 -0
- package/dist/api/middleware/auth-federation.js.map +1 -0
- package/dist/api/middleware/auth.js +545 -0
- package/dist/api/middleware/auth.js.map +1 -0
- package/dist/db/actions.js +212 -0
- package/dist/db/actions.js.map +1 -0
- package/dist/db/auth.js +506 -0
- package/dist/db/auth.js.map +1 -0
- package/dist/db/branches.js +65 -0
- package/dist/db/branches.js.map +1 -0
- package/dist/db/clickhouse.js +1074 -0
- package/dist/db/clickhouse.js.map +1 -0
- package/dist/db/dlq.js +39 -0
- package/dist/db/dlq.js.map +1 -0
- package/dist/db/events.js +28 -0
- package/dist/db/events.js.map +1 -0
- package/dist/db/exec.js +64 -0
- package/dist/db/exec.js.map +1 -0
- package/dist/db/files.js +85 -0
- package/dist/db/files.js.map +1 -0
- package/dist/db/flags.js +24 -0
- package/dist/db/flags.js.map +1 -0
- package/dist/db/git.js +116 -0
- package/dist/db/git.js.map +1 -0
- package/dist/db/iceberg/inverted-index.js +862 -0
- package/dist/db/iceberg/inverted-index.js.map +1 -0
- package/dist/db/iceberg/puffin.js +878 -0
- package/dist/db/iceberg/puffin.js.map +1 -0
- package/dist/db/iceberg/search-manifest.js +422 -0
- package/dist/db/iceberg/search-manifest.js.map +1 -0
- package/dist/db/iceberg/types.js +8 -0
- package/dist/db/iceberg/types.js.map +1 -0
- package/dist/db/index.js +121 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/integrations.js +368 -0
- package/dist/db/integrations.js.map +1 -0
- package/dist/db/json-indexes.js +332 -0
- package/dist/db/json-indexes.js.map +1 -0
- package/dist/db/linked-accounts.js +287 -0
- package/dist/db/linked-accounts.js.map +1 -0
- package/dist/db/nouns.js +183 -0
- package/dist/db/nouns.js.map +1 -0
- package/dist/db/objects.js +170 -0
- package/dist/db/objects.js.map +1 -0
- package/dist/db/primitives/dag-scheduler/index.js +869 -0
- package/dist/db/primitives/dag-scheduler/index.js.map +1 -0
- package/dist/db/primitives/exactly-once-context.js +237 -0
- package/dist/db/primitives/exactly-once-context.js.map +1 -0
- package/dist/db/primitives/index.js +62 -0
- package/dist/db/primitives/index.js.map +1 -0
- package/dist/db/primitives/keyed-router.js +145 -0
- package/dist/db/primitives/keyed-router.js.map +1 -0
- package/dist/db/primitives/observability.js +162 -0
- package/dist/db/primitives/observability.js.map +1 -0
- package/dist/db/primitives/schema-evolution.js +643 -0
- package/dist/db/primitives/schema-evolution.js.map +1 -0
- package/dist/db/primitives/stateful-operator/index.js +770 -0
- package/dist/db/primitives/stateful-operator/index.js.map +1 -0
- package/dist/db/primitives/temporal-store.js +306 -0
- package/dist/db/primitives/temporal-store.js.map +1 -0
- package/dist/db/primitives/typed-column-store.js +1229 -0
- package/dist/db/primitives/typed-column-store.js.map +1 -0
- package/dist/db/primitives/utils/duration.js +162 -0
- package/dist/db/primitives/utils/duration.js.map +1 -0
- package/dist/db/primitives/utils/murmur3.js +116 -0
- package/dist/db/primitives/utils/murmur3.js.map +1 -0
- package/dist/db/primitives/watermark-service.js +136 -0
- package/dist/db/primitives/watermark-service.js.map +1 -0
- package/dist/db/primitives/window-manager.js +764 -0
- package/dist/db/primitives/window-manager.js.map +1 -0
- package/dist/db/relationships.js +66 -0
- package/dist/db/relationships.js.map +1 -0
- package/dist/db/schema-minimal.js +61 -0
- package/dist/db/schema-minimal.js.map +1 -0
- package/dist/db/search.js +28 -0
- package/dist/db/search.js.map +1 -0
- package/dist/db/stores.js +1665 -0
- package/dist/db/stores.js.map +1 -0
- package/dist/db/things.js +297 -0
- package/dist/db/things.js.map +1 -0
- package/dist/db/vault.js +171 -0
- package/dist/db/vault.js.map +1 -0
- package/dist/db/verbs.js +102 -0
- package/dist/db/verbs.js.map +1 -0
- package/dist/do/base.js +48 -0
- package/dist/do/base.js.map +1 -0
- package/dist/do/tiny.js +31 -0
- package/dist/do/tiny.js.map +1 -0
- package/dist/lib/DOAuth.js +261 -0
- package/dist/lib/DOAuth.js.map +1 -0
- package/dist/lib/DODispatcher.js +72 -0
- package/dist/lib/DODispatcher.js.map +1 -0
- package/dist/lib/Modifier.js +189 -0
- package/dist/lib/Modifier.js.map +1 -0
- package/dist/lib/StateStorage.js +403 -0
- package/dist/lib/StateStorage.js.map +1 -0
- package/dist/lib/TypeRegistry.js +122 -0
- package/dist/lib/TypeRegistry.js.map +1 -0
- package/dist/lib/ai/gateway.js +247 -0
- package/dist/lib/ai/gateway.js.map +1 -0
- package/dist/lib/ai/tool-loop-agent.js +591 -0
- package/dist/lib/ai/tool-loop-agent.js.map +1 -0
- package/dist/lib/auto-wiring.js +439 -0
- package/dist/lib/auto-wiring.js.map +1 -0
- package/dist/lib/browse/browserbase.js +163 -0
- package/dist/lib/browse/browserbase.js.map +1 -0
- package/dist/lib/browse/cloudflare.js +144 -0
- package/dist/lib/browse/cloudflare.js.map +1 -0
- package/dist/lib/browse/index.js +62 -0
- package/dist/lib/browse/index.js.map +1 -0
- package/dist/lib/browse/types.js +13 -0
- package/dist/lib/browse/types.js.map +1 -0
- package/dist/lib/cache/index.js +37 -0
- package/dist/lib/cache/index.js.map +1 -0
- package/dist/lib/cache/visibility.js +638 -0
- package/dist/lib/cache/visibility.js.map +1 -0
- package/dist/lib/capabilities.js +268 -0
- package/dist/lib/capabilities.js.map +1 -0
- package/dist/lib/channels/base.js +106 -0
- package/dist/lib/channels/base.js.map +1 -0
- package/dist/lib/channels/discord.js +94 -0
- package/dist/lib/channels/discord.js.map +1 -0
- package/dist/lib/channels/email.js +204 -0
- package/dist/lib/channels/email.js.map +1 -0
- package/dist/lib/channels/index.js +90 -0
- package/dist/lib/channels/index.js.map +1 -0
- package/dist/lib/channels/mdxui-chat.js +95 -0
- package/dist/lib/channels/mdxui-chat.js.map +1 -0
- package/dist/lib/channels/slack-blockkit.js +121 -0
- package/dist/lib/channels/slack-blockkit.js.map +1 -0
- package/dist/lib/channels/types.js +7 -0
- package/dist/lib/channels/types.js.map +1 -0
- package/dist/lib/cloudflare/ai.js +654 -0
- package/dist/lib/cloudflare/ai.js.map +1 -0
- package/dist/lib/cloudflare/index.js +88 -0
- package/dist/lib/cloudflare/index.js.map +1 -0
- package/dist/lib/cloudflare/kv.js +342 -0
- package/dist/lib/cloudflare/kv.js.map +1 -0
- package/dist/lib/cloudflare/queues.js +434 -0
- package/dist/lib/cloudflare/queues.js.map +1 -0
- package/dist/lib/cloudflare/r2.js +604 -0
- package/dist/lib/cloudflare/r2.js.map +1 -0
- package/dist/lib/cloudflare/vectorize.js +494 -0
- package/dist/lib/cloudflare/vectorize.js.map +1 -0
- package/dist/lib/cloudflare/workflows.js +569 -0
- package/dist/lib/cloudflare/workflows.js.map +1 -0
- package/dist/lib/colo/caching.js +196 -0
- package/dist/lib/colo/caching.js.map +1 -0
- package/dist/lib/colo/detection.js +194 -0
- package/dist/lib/colo/detection.js.map +1 -0
- package/dist/lib/colo/external-data.js +219 -0
- package/dist/lib/colo/external-data.js.map +1 -0
- package/dist/lib/colo/globe-data.js +179 -0
- package/dist/lib/colo/globe-data.js.map +1 -0
- package/dist/lib/colo/index.js +16 -0
- package/dist/lib/colo/index.js.map +1 -0
- package/dist/lib/decorators.js +37 -0
- package/dist/lib/decorators.js.map +1 -0
- package/dist/lib/discovery.js +81 -0
- package/dist/lib/discovery.js.map +1 -0
- package/dist/lib/executors/AgenticFunctionExecutor.js +619 -0
- package/dist/lib/executors/AgenticFunctionExecutor.js.map +1 -0
- package/dist/lib/executors/BaseFunctionExecutor.js +328 -0
- package/dist/lib/executors/BaseFunctionExecutor.js.map +1 -0
- package/dist/lib/executors/CascadeExecutor.js +418 -0
- package/dist/lib/executors/CascadeExecutor.js.map +1 -0
- package/dist/lib/executors/CodeFunctionExecutor.js +904 -0
- package/dist/lib/executors/CodeFunctionExecutor.js.map +1 -0
- package/dist/lib/executors/GenerativeFunctionExecutor.js +904 -0
- package/dist/lib/executors/GenerativeFunctionExecutor.js.map +1 -0
- package/dist/lib/executors/HumanFunctionExecutor.js +884 -0
- package/dist/lib/executors/HumanFunctionExecutor.js.map +1 -0
- package/dist/lib/executors/ParallelStepExecutor.js +308 -0
- package/dist/lib/executors/ParallelStepExecutor.js.map +1 -0
- package/dist/lib/executors/types.js +12 -0
- package/dist/lib/executors/types.js.map +1 -0
- package/dist/lib/experiments.js +89 -0
- package/dist/lib/experiments.js.map +1 -0
- package/dist/lib/flags/store.js +262 -0
- package/dist/lib/flags/store.js.map +1 -0
- package/dist/lib/functions/FunctionComposition.js +467 -0
- package/dist/lib/functions/FunctionComposition.js.map +1 -0
- package/dist/lib/functions/FunctionMiddleware.js +457 -0
- package/dist/lib/functions/FunctionMiddleware.js.map +1 -0
- package/dist/lib/functions/FunctionRegistry.js +426 -0
- package/dist/lib/functions/FunctionRegistry.js.map +1 -0
- package/dist/lib/functions/createFunction.js +1048 -0
- package/dist/lib/functions/createFunction.js.map +1 -0
- package/dist/lib/humans/index.js +68 -0
- package/dist/lib/humans/index.js.map +1 -0
- package/dist/lib/humans/templates.js +117 -0
- package/dist/lib/humans/templates.js.map +1 -0
- package/dist/lib/identity.js +98 -0
- package/dist/lib/identity.js.map +1 -0
- package/dist/lib/index.js +9 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/logging/error-logger.js +163 -0
- package/dist/lib/logging/error-logger.js.map +1 -0
- package/dist/lib/logging/index.js +160 -0
- package/dist/lib/logging/index.js.map +1 -0
- package/dist/lib/mixins/bash.js +753 -0
- package/dist/lib/mixins/bash.js.map +1 -0
- package/dist/lib/mixins/fs.js +648 -0
- package/dist/lib/mixins/fs.js.map +1 -0
- package/dist/lib/mixins/git.js +1006 -0
- package/dist/lib/mixins/git.js.map +1 -0
- package/dist/lib/mixins/npm.js +662 -0
- package/dist/lib/mixins/npm.js.map +1 -0
- package/dist/lib/noun-id.js +278 -0
- package/dist/lib/noun-id.js.map +1 -0
- package/dist/lib/rate-limit/sliding-window.js +148 -0
- package/dist/lib/rate-limit/sliding-window.js.map +1 -0
- package/dist/lib/rate-limit.js +110 -0
- package/dist/lib/rate-limit.js.map +1 -0
- package/dist/lib/rpc/bindings.js +548 -0
- package/dist/lib/rpc/bindings.js.map +1 -0
- package/dist/lib/rpc/index.js +64 -0
- package/dist/lib/rpc/index.js.map +1 -0
- package/dist/lib/safe-stringify.js +223 -0
- package/dist/lib/safe-stringify.js.map +1 -0
- package/dist/lib/sandbox/miniflare-sandbox.js +1007 -0
- package/dist/lib/sandbox/miniflare-sandbox.js.map +1 -0
- package/dist/lib/sqids.js +110 -0
- package/dist/lib/sqids.js.map +1 -0
- package/dist/lib/sql/adapters/index.js +10 -0
- package/dist/lib/sql/adapters/index.js.map +1 -0
- package/dist/lib/sql/adapters/node-sql-parser.js +552 -0
- package/dist/lib/sql/adapters/node-sql-parser.js.map +1 -0
- package/dist/lib/sql/adapters/pgsql-parser.js +1190 -0
- package/dist/lib/sql/adapters/pgsql-parser.js.map +1 -0
- package/dist/lib/sql/index.js +277 -0
- package/dist/lib/sql/index.js.map +1 -0
- package/dist/lib/sql/types.js +56 -0
- package/dist/lib/sql/types.js.map +1 -0
- package/dist/lib/type-classifier.js +126 -0
- package/dist/lib/type-classifier.js.map +1 -0
- package/dist/lib/utils/html.js +47 -0
- package/dist/lib/utils/html.js.map +1 -0
- package/dist/lib/validation.js +48 -0
- package/dist/lib/validation.js.map +1 -0
- package/dist/lib/vault/store.js +411 -0
- package/dist/lib/vault/store.js.map +1 -0
- package/dist/metrics/hunch.js +739 -0
- package/dist/metrics/hunch.js.map +1 -0
- package/dist/objects/API.js +302 -0
- package/dist/objects/API.js.map +1 -0
- package/dist/objects/Agent.js +179 -0
- package/dist/objects/Agent.js.map +1 -0
- package/dist/objects/AgenticFunctionExecutor.js +8 -0
- package/dist/objects/AgenticFunctionExecutor.js.map +1 -0
- package/dist/objects/App.js +83 -0
- package/dist/objects/App.js.map +1 -0
- package/dist/objects/Browser.js +884 -0
- package/dist/objects/Browser.js.map +1 -0
- package/dist/objects/Business.js +107 -0
- package/dist/objects/Business.js.map +1 -0
- package/dist/objects/CLI.js +221 -0
- package/dist/objects/CLI.js.map +1 -0
- package/dist/objects/CodeFunctionExecutor.js +8 -0
- package/dist/objects/CodeFunctionExecutor.js.map +1 -0
- package/dist/objects/Collection.js +161 -0
- package/dist/objects/Collection.js.map +1 -0
- package/dist/objects/DO.js +41 -0
- package/dist/objects/DO.js.map +1 -0
- package/dist/objects/DOBase.js +2309 -0
- package/dist/objects/DOBase.js.map +1 -0
- package/dist/objects/DOCache.js +153 -0
- package/dist/objects/DOCache.js.map +1 -0
- package/dist/objects/DOFull.js +1676 -0
- package/dist/objects/DOFull.js.map +1 -0
- package/dist/objects/DOTiny.js +207 -0
- package/dist/objects/DOTiny.js.map +1 -0
- package/dist/objects/Directory.js +199 -0
- package/dist/objects/Directory.js.map +1 -0
- package/dist/objects/Entity.js +413 -0
- package/dist/objects/Entity.js.map +1 -0
- package/dist/objects/Function.js +116 -0
- package/dist/objects/Function.js.map +1 -0
- package/dist/objects/Human.js +231 -0
- package/dist/objects/Human.js.map +1 -0
- package/dist/objects/HumanFunctionExecutor.js +8 -0
- package/dist/objects/HumanFunctionExecutor.js.map +1 -0
- package/dist/objects/IcebergMetadataDO.js +938 -0
- package/dist/objects/IcebergMetadataDO.js.map +1 -0
- package/dist/objects/IntegrationsDO.js +1174 -0
- package/dist/objects/IntegrationsDO.js.map +1 -0
- package/dist/objects/ObservabilityBroadcaster.js +149 -0
- package/dist/objects/ObservabilityBroadcaster.js.map +1 -0
- package/dist/objects/Package.js +154 -0
- package/dist/objects/Package.js.map +1 -0
- package/dist/objects/Product.js +193 -0
- package/dist/objects/Product.js.map +1 -0
- package/dist/objects/SDK.js +152 -0
- package/dist/objects/SDK.js.map +1 -0
- package/dist/objects/SaaS.js +235 -0
- package/dist/objects/SaaS.js.map +1 -0
- package/dist/objects/SandboxDO.js +759 -0
- package/dist/objects/SandboxDO.js.map +1 -0
- package/dist/objects/Service.js +337 -0
- package/dist/objects/Service.js.map +1 -0
- package/dist/objects/Site.js +80 -0
- package/dist/objects/Site.js.map +1 -0
- package/dist/objects/Startup.js +479 -0
- package/dist/objects/Startup.js.map +1 -0
- package/dist/objects/ThingsDO.js +170 -0
- package/dist/objects/ThingsDO.js.map +1 -0
- package/dist/objects/VectorShardDO.js +650 -0
- package/dist/objects/VectorShardDO.js.map +1 -0
- package/dist/objects/Worker.js +144 -0
- package/dist/objects/Worker.js.map +1 -0
- package/dist/objects/Workflow.js +196 -0
- package/dist/objects/Workflow.js.map +1 -0
- package/dist/objects/WorkflowFactory.js +313 -0
- package/dist/objects/WorkflowFactory.js.map +1 -0
- package/dist/objects/WorkflowRuntime.js +863 -0
- package/dist/objects/WorkflowRuntime.js.map +1 -0
- package/dist/objects/circuit-breaker-bulkhead.js +178 -0
- package/dist/objects/circuit-breaker-bulkhead.js.map +1 -0
- package/dist/objects/createFunction.js +934 -0
- package/dist/objects/createFunction.js.map +1 -0
- package/dist/objects/index.js +80 -0
- package/dist/objects/index.js.map +1 -0
- package/dist/objects/lifecycle/Branch.js +275 -0
- package/dist/objects/lifecycle/Branch.js.map +1 -0
- package/dist/objects/lifecycle/Clone.js +1499 -0
- package/dist/objects/lifecycle/Clone.js.map +1 -0
- package/dist/objects/lifecycle/Compact.js +237 -0
- package/dist/objects/lifecycle/Compact.js.map +1 -0
- package/dist/objects/lifecycle/Promote.js +476 -0
- package/dist/objects/lifecycle/Promote.js.map +1 -0
- package/dist/objects/lifecycle/Shard.js +560 -0
- package/dist/objects/lifecycle/Shard.js.map +1 -0
- package/dist/objects/lifecycle/index.js +15 -0
- package/dist/objects/lifecycle/index.js.map +1 -0
- package/dist/objects/lifecycle/types.js +33 -0
- package/dist/objects/lifecycle/types.js.map +1 -0
- package/dist/objects/mixins/infrastructure.js +171 -0
- package/dist/objects/mixins/infrastructure.js.map +1 -0
- package/dist/objects/modules/StoresModule.js +153 -0
- package/dist/objects/modules/StoresModule.js.map +1 -0
- package/dist/objects/persistence/checkpoint-manager.js +606 -0
- package/dist/objects/persistence/checkpoint-manager.js.map +1 -0
- package/dist/objects/persistence/index.js +72 -0
- package/dist/objects/persistence/index.js.map +1 -0
- package/dist/objects/persistence/migration-runner.js +562 -0
- package/dist/objects/persistence/migration-runner.js.map +1 -0
- package/dist/objects/persistence/replication-manager.js +501 -0
- package/dist/objects/persistence/replication-manager.js.map +1 -0
- package/dist/objects/persistence/tiered-storage-manager.js +595 -0
- package/dist/objects/persistence/tiered-storage-manager.js.map +1 -0
- package/dist/objects/persistence/types.js +14 -0
- package/dist/objects/persistence/types.js.map +1 -0
- package/dist/objects/persistence/wal-manager.js +653 -0
- package/dist/objects/persistence/wal-manager.js.map +1 -0
- package/dist/objects/presets/index.js +20 -0
- package/dist/objects/presets/index.js.map +1 -0
- package/dist/objects/presets/primitives.js +188 -0
- package/dist/objects/presets/primitives.js.map +1 -0
- package/dist/objects/primitives/alarm-adapter.js +141 -0
- package/dist/objects/primitives/alarm-adapter.js.map +1 -0
- package/dist/objects/primitives/index.js +337 -0
- package/dist/objects/primitives/index.js.map +1 -0
- package/dist/objects/primitives/storage-adapter.js +182 -0
- package/dist/objects/primitives/storage-adapter.js.map +1 -0
- package/dist/objects/primitives/with-primitives.js +102 -0
- package/dist/objects/primitives/with-primitives.js.map +1 -0
- package/dist/objects/services/StoreManager.js +227 -0
- package/dist/objects/services/StoreManager.js.map +1 -0
- package/dist/objects/services/index.js +13 -0
- package/dist/objects/services/index.js.map +1 -0
- package/dist/objects/transport/auth-layer.js +1451 -0
- package/dist/objects/transport/auth-layer.js.map +1 -0
- package/dist/objects/transport/capnweb-target.js +355 -0
- package/dist/objects/transport/capnweb-target.js.map +1 -0
- package/dist/objects/transport/chain.js +441 -0
- package/dist/objects/transport/chain.js.map +1 -0
- package/dist/objects/transport/handler.js +58 -0
- package/dist/objects/transport/handler.js.map +1 -0
- package/dist/objects/transport/index.js +53 -0
- package/dist/objects/transport/index.js.map +1 -0
- package/dist/objects/transport/mcp-server.js +691 -0
- package/dist/objects/transport/mcp-server.js.map +1 -0
- package/dist/objects/transport/rest-autowire.js +1508 -0
- package/dist/objects/transport/rest-autowire.js.map +1 -0
- package/dist/objects/transport/rest-router.js +440 -0
- package/dist/objects/transport/rest-router.js.map +1 -0
- package/dist/objects/transport/rpc-server.js +1539 -0
- package/dist/objects/transport/rpc-server.js.map +1 -0
- package/dist/objects/transport/shared.js +576 -0
- package/dist/objects/transport/shared.js.map +1 -0
- package/dist/objects/transport/sync-engine.js +291 -0
- package/dist/objects/transport/sync-engine.js.map +1 -0
- package/dist/objects/transport/types.js +8 -0
- package/dist/objects/transport/types.js.map +1 -0
- package/dist/sandbox/index.js +258 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/snippets/artifacts-config.js +241 -0
- package/dist/snippets/artifacts-config.js.map +1 -0
- package/dist/snippets/artifacts-ingest.js +832 -0
- package/dist/snippets/artifacts-ingest.js.map +1 -0
- package/dist/snippets/artifacts-serve.js +1035 -0
- package/dist/snippets/artifacts-serve.js.map +1 -0
- package/dist/snippets/artifacts-types.js +161 -0
- package/dist/snippets/artifacts-types.js.map +1 -0
- package/dist/snippets/cache-probe.js +376 -0
- package/dist/snippets/cache-probe.js.map +1 -0
- package/dist/snippets/cache.js +10 -0
- package/dist/snippets/cache.js.map +1 -0
- package/dist/snippets/events.js +469 -0
- package/dist/snippets/events.js.map +1 -0
- package/dist/snippets/index.js +7 -0
- package/dist/snippets/index.js.map +1 -0
- package/dist/snippets/proxy.js +495 -0
- package/dist/snippets/proxy.js.map +1 -0
- package/dist/snippets/search.js +1759 -0
- package/dist/snippets/search.js.map +1 -0
- package/dist/streams/index.js +30 -0
- package/dist/streams/index.js.map +1 -0
- package/dist/streams/observability.js +68 -0
- package/dist/streams/observability.js.map +1 -0
- package/dist/types/AI.js +92 -0
- package/dist/types/AI.js.map +1 -0
- package/dist/types/AIFunction.js +171 -0
- package/dist/types/AIFunction.js.map +1 -0
- package/dist/types/BrowseVerb.js +89 -0
- package/dist/types/BrowseVerb.js.map +1 -0
- package/dist/types/Browser.js +31 -0
- package/dist/types/Browser.js.map +1 -0
- package/dist/types/Chaos.js +15 -0
- package/dist/types/Chaos.js.map +1 -0
- package/dist/types/CloudflareBindings.js +109 -0
- package/dist/types/CloudflareBindings.js.map +1 -0
- package/dist/types/Collection.js +50 -0
- package/dist/types/Collection.js.map +1 -0
- package/dist/types/DO.js +2 -0
- package/dist/types/DO.js.map +1 -0
- package/dist/types/DOLocation.js +63 -0
- package/dist/types/DOLocation.js.map +1 -0
- package/dist/types/EventHandler.js +57 -0
- package/dist/types/EventHandler.js.map +1 -0
- package/dist/types/Experiment.js +33 -0
- package/dist/types/Experiment.js.map +1 -0
- package/dist/types/Flag.js +57 -0
- package/dist/types/Flag.js.map +1 -0
- package/dist/types/Lifecycle.js +13 -0
- package/dist/types/Lifecycle.js.map +1 -0
- package/dist/types/Location.js +169 -0
- package/dist/types/Location.js.map +1 -0
- package/dist/types/Noun.js +66 -0
- package/dist/types/Noun.js.map +1 -0
- package/dist/types/SessionEvent.js +194 -0
- package/dist/types/SessionEvent.js.map +1 -0
- package/dist/types/Thing.js +55 -0
- package/dist/types/Thing.js.map +1 -0
- package/dist/types/ThingDO.js +153 -0
- package/dist/types/ThingDO.js.map +1 -0
- package/dist/types/Things.js +2 -0
- package/dist/types/Things.js.map +1 -0
- package/dist/types/Verb.js +119 -0
- package/dist/types/Verb.js.map +1 -0
- package/dist/types/WorkflowContext.js +70 -0
- package/dist/types/WorkflowContext.js.map +1 -0
- package/dist/types/analytics-api.js +13 -0
- package/dist/types/analytics-api.js.map +1 -0
- package/dist/types/capabilities.js +135 -0
- package/dist/types/capabilities.js.map +1 -0
- package/dist/types/drizzle.js +12 -0
- package/dist/types/drizzle.js.map +1 -0
- package/dist/types/event.js +201 -0
- package/dist/types/event.js.map +1 -0
- package/dist/types/fn.js +12 -0
- package/dist/types/fn.js.map +1 -0
- package/dist/types/iceberg.js +48 -0
- package/dist/types/iceberg.js.map +1 -0
- package/dist/types/ids.js +170 -0
- package/dist/types/ids.js.map +1 -0
- package/dist/types/index.js +41 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/introspect.js +54 -0
- package/dist/types/introspect.js.map +1 -0
- package/dist/types/observability.js +124 -0
- package/dist/types/observability.js.map +1 -0
- package/dist/types/sync-protocol.js +175 -0
- package/dist/types/sync-protocol.js.map +1 -0
- package/dist/types/vector.js +13 -0
- package/dist/types/vector.js.map +1 -0
- package/dist/workflows/ScheduleManager.js +473 -0
- package/dist/workflows/ScheduleManager.js.map +1 -0
- package/dist/workflows/StepDOBridge.js +149 -0
- package/dist/workflows/StepDOBridge.js.map +1 -0
- package/dist/workflows/StepResultStorage.js +232 -0
- package/dist/workflows/StepResultStorage.js.map +1 -0
- package/dist/workflows/WaitForEventManager.js +461 -0
- package/dist/workflows/WaitForEventManager.js.map +1 -0
- package/dist/workflows/analyzer.js +332 -0
- package/dist/workflows/analyzer.js.map +1 -0
- package/dist/workflows/compat/activity-router.js +484 -0
- package/dist/workflows/compat/activity-router.js.map +1 -0
- package/dist/workflows/compat/backends/cloudflare-workflows.js +431 -0
- package/dist/workflows/compat/backends/cloudflare-workflows.js.map +1 -0
- package/dist/workflows/compat/backends/index.js +14 -0
- package/dist/workflows/compat/backends/index.js.map +1 -0
- package/dist/workflows/compat/errors/index.js +375 -0
- package/dist/workflows/compat/errors/index.js.map +1 -0
- package/dist/workflows/compat/index.js +79 -0
- package/dist/workflows/compat/index.js.map +1 -0
- package/dist/workflows/compat/inngest/index.js +989 -0
- package/dist/workflows/compat/inngest/index.js.map +1 -0
- package/dist/workflows/compat/qstash/index.js +1263 -0
- package/dist/workflows/compat/qstash/index.js.map +1 -0
- package/dist/workflows/compat/temporal/activities.js +739 -0
- package/dist/workflows/compat/temporal/activities.js.map +1 -0
- package/dist/workflows/compat/temporal/child-workflows.js +154 -0
- package/dist/workflows/compat/temporal/child-workflows.js.map +1 -0
- package/dist/workflows/compat/temporal/client.js +381 -0
- package/dist/workflows/compat/temporal/client.js.map +1 -0
- package/dist/workflows/compat/temporal/context.js +309 -0
- package/dist/workflows/compat/temporal/context.js.map +1 -0
- package/dist/workflows/compat/temporal/determinism.js +216 -0
- package/dist/workflows/compat/temporal/determinism.js.map +1 -0
- package/dist/workflows/compat/temporal/errors.js +128 -0
- package/dist/workflows/compat/temporal/errors.js.map +1 -0
- package/dist/workflows/compat/temporal/index.js +2464 -0
- package/dist/workflows/compat/temporal/index.js.map +1 -0
- package/dist/workflows/compat/temporal/saga.js +504 -0
- package/dist/workflows/compat/temporal/saga.js.map +1 -0
- package/dist/workflows/compat/temporal/signals.js +364 -0
- package/dist/workflows/compat/temporal/signals.js.map +1 -0
- package/dist/workflows/compat/temporal/storage.js +271 -0
- package/dist/workflows/compat/temporal/storage.js.map +1 -0
- package/dist/workflows/compat/temporal/timers.js +347 -0
- package/dist/workflows/compat/temporal/timers.js.map +1 -0
- package/dist/workflows/compat/temporal/types.js +7 -0
- package/dist/workflows/compat/temporal/types.js.map +1 -0
- package/dist/workflows/compat/temporal/unified-primitives.js +339 -0
- package/dist/workflows/compat/temporal/unified-primitives.js.map +1 -0
- package/dist/workflows/compat/trigger/index.js +468 -0
- package/dist/workflows/compat/trigger/index.js.map +1 -0
- package/dist/workflows/compat/utils/index.js +69 -0
- package/dist/workflows/compat/utils/index.js.map +1 -0
- package/dist/workflows/context/correlation-capability.js +266 -0
- package/dist/workflows/context/correlation-capability.js.map +1 -0
- package/dist/workflows/context/correlation.js +484 -0
- package/dist/workflows/context/correlation.js.map +1 -0
- package/dist/workflows/context/experiment.js +289 -0
- package/dist/workflows/context/experiment.js.map +1 -0
- package/dist/workflows/context/flag.js +244 -0
- package/dist/workflows/context/flag.js.map +1 -0
- package/dist/workflows/context/foundation.js +648 -0
- package/dist/workflows/context/foundation.js.map +1 -0
- package/dist/workflows/context/human-base.js +106 -0
- package/dist/workflows/context/human-base.js.map +1 -0
- package/dist/workflows/context/human.js +368 -0
- package/dist/workflows/context/human.js.map +1 -0
- package/dist/workflows/context/measure.js +354 -0
- package/dist/workflows/context/measure.js.map +1 -0
- package/dist/workflows/context/rate-limit.js +358 -0
- package/dist/workflows/context/rate-limit.js.map +1 -0
- package/dist/workflows/context/user.js +117 -0
- package/dist/workflows/context/user.js.map +1 -0
- package/dist/workflows/context/vault.js +360 -0
- package/dist/workflows/context/vault.js.map +1 -0
- package/dist/workflows/data/entity-events/entity-events.js +489 -0
- package/dist/workflows/data/entity-events/entity-events.js.map +1 -0
- package/dist/workflows/data/experiment/index.js +599 -0
- package/dist/workflows/data/experiment/index.js.map +1 -0
- package/dist/workflows/data/goal/context.js +558 -0
- package/dist/workflows/data/goal/context.js.map +1 -0
- package/dist/workflows/data/goal/index.js +32 -0
- package/dist/workflows/data/goal/index.js.map +1 -0
- package/dist/workflows/data/measure/index.js +840 -0
- package/dist/workflows/data/measure/index.js.map +1 -0
- package/dist/workflows/data/stream/index.js +1149 -0
- package/dist/workflows/data/stream/index.js.map +1 -0
- package/dist/workflows/data/track/context.js +883 -0
- package/dist/workflows/data/track/context.js.map +1 -0
- package/dist/workflows/data/track/index.js +15 -0
- package/dist/workflows/data/track/index.js.map +1 -0
- package/dist/workflows/data/view/context.js +864 -0
- package/dist/workflows/data/view/context.js.map +1 -0
- package/dist/workflows/domain.js +93 -0
- package/dist/workflows/domain.js.map +1 -0
- package/dist/workflows/flag.js +176 -0
- package/dist/workflows/flag.js.map +1 -0
- package/dist/workflows/flags.js +217 -0
- package/dist/workflows/flags.js.map +1 -0
- package/dist/workflows/hash.js +209 -0
- package/dist/workflows/hash.js.map +1 -0
- package/dist/workflows/index.js +50 -0
- package/dist/workflows/index.js.map +1 -0
- package/dist/workflows/on.js +378 -0
- package/dist/workflows/on.js.map +1 -0
- package/dist/workflows/pipeline-promise.js +481 -0
- package/dist/workflows/pipeline-promise.js.map +1 -0
- package/dist/workflows/pipeline-types.js +20 -0
- package/dist/workflows/pipeline-types.js.map +1 -0
- package/dist/workflows/proxy.js +76 -0
- package/dist/workflows/proxy.js.map +1 -0
- package/dist/workflows/runtime.js +310 -0
- package/dist/workflows/runtime.js.map +1 -0
- package/dist/workflows/schedule-builder.js +327 -0
- package/dist/workflows/schedule-builder.js.map +1 -0
- package/dist/workflows/visibility/index.js +146 -0
- package/dist/workflows/visibility/index.js.map +1 -0
- package/dist/workflows/visibility/query-parser.js +150 -0
- package/dist/workflows/visibility/query-parser.js.map +1 -0
- package/dist/workflows/visibility/store.js +223 -0
- package/dist/workflows/visibility/store.js.map +1 -0
- package/dist/workflows/visibility/types.js +30 -0
- package/dist/workflows/visibility/types.js.map +1 -0
- package/dist/workflows/workflow.js +53 -0
- package/dist/workflows/workflow.js.map +1 -0
- package/package.json +294 -46
|
@@ -0,0 +1,759 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SandboxDO - Durable Object for code execution sandboxes
|
|
3
|
+
*
|
|
4
|
+
* Provides HTTP routes for interacting with Cloudflare Sandbox:
|
|
5
|
+
* - POST /create - Create sandbox session
|
|
6
|
+
* - POST /exec - Execute command
|
|
7
|
+
* - POST /exec/stream - Execute command with SSE streaming
|
|
8
|
+
* - POST /file/write - Write file
|
|
9
|
+
* - GET /file/read - Read file
|
|
10
|
+
* - POST /port/expose - Expose port
|
|
11
|
+
* - GET /ports - List exposed ports
|
|
12
|
+
* - GET /state - Get session state
|
|
13
|
+
* - POST /destroy - Destroy sandbox
|
|
14
|
+
* - GET /terminal - WebSocket terminal upgrade
|
|
15
|
+
*
|
|
16
|
+
* Terminal WebSocket Protocol:
|
|
17
|
+
* Client -> Server:
|
|
18
|
+
* { type: 'input', data: string } - Send input to stdin
|
|
19
|
+
* { type: 'resize', cols: number, rows: number } - Resize terminal
|
|
20
|
+
* { type: 'execute', command: string } - Execute command
|
|
21
|
+
* Server -> Client:
|
|
22
|
+
* { type: 'output', data: string } - stdout output
|
|
23
|
+
* { type: 'error', data: string } - stderr output (with ANSI codes)
|
|
24
|
+
* { type: 'exit', code: number } - Process exit
|
|
25
|
+
* { type: 'connected', sessionId: string } - Connection established
|
|
26
|
+
*/
|
|
27
|
+
import { Hono } from 'hono';
|
|
28
|
+
import { DO } from './DO';
|
|
29
|
+
import { getSandbox, } from '../sandbox';
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Ring Buffer for Output Preservation (64KB max)
|
|
32
|
+
// ============================================================================
|
|
33
|
+
/**
|
|
34
|
+
* Ring buffer that preserves last 64KB of output for reconnection
|
|
35
|
+
*/
|
|
36
|
+
class RingBuffer {
|
|
37
|
+
buffer = [];
|
|
38
|
+
totalSize = 0;
|
|
39
|
+
maxSize;
|
|
40
|
+
constructor(maxSize = 64 * 1024) {
|
|
41
|
+
this.maxSize = maxSize;
|
|
42
|
+
}
|
|
43
|
+
push(data) {
|
|
44
|
+
this.buffer.push(data);
|
|
45
|
+
this.totalSize += data.length;
|
|
46
|
+
// Evict oldest entries if over size limit
|
|
47
|
+
while (this.totalSize > this.maxSize && this.buffer.length > 0) {
|
|
48
|
+
const removed = this.buffer.shift();
|
|
49
|
+
this.totalSize -= removed.length;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
getAll() {
|
|
53
|
+
return this.buffer.join('');
|
|
54
|
+
}
|
|
55
|
+
clear() {
|
|
56
|
+
this.buffer = [];
|
|
57
|
+
this.totalSize = 0;
|
|
58
|
+
}
|
|
59
|
+
get size() {
|
|
60
|
+
return this.totalSize;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// ============================================================================
|
|
64
|
+
// SandboxDO Class
|
|
65
|
+
// ============================================================================
|
|
66
|
+
export class SandboxDO extends DO {
|
|
67
|
+
static $type = 'Sandbox';
|
|
68
|
+
sandbox = null;
|
|
69
|
+
legacySessionId = null;
|
|
70
|
+
legacyCreatedAt = null;
|
|
71
|
+
legacySessionStatus = 'idle';
|
|
72
|
+
// New session state for lifecycle API
|
|
73
|
+
session = null;
|
|
74
|
+
// Terminal WebSocket state
|
|
75
|
+
terminalSessions = new Map();
|
|
76
|
+
app;
|
|
77
|
+
constructor(ctx, env) {
|
|
78
|
+
super(ctx, env);
|
|
79
|
+
this.app = this.createRoutes();
|
|
80
|
+
// Load persisted session on construction
|
|
81
|
+
this.loadSession();
|
|
82
|
+
}
|
|
83
|
+
// --------------------------------------------------------------------------
|
|
84
|
+
// New Session Lifecycle API (TDD)
|
|
85
|
+
// --------------------------------------------------------------------------
|
|
86
|
+
/**
|
|
87
|
+
* Create a new sandbox session
|
|
88
|
+
*/
|
|
89
|
+
async create(options) {
|
|
90
|
+
// Check if Sandbox namespace is configured
|
|
91
|
+
if (!this.env.Sandbox) {
|
|
92
|
+
throw new Error('Sandbox namespace not configured');
|
|
93
|
+
}
|
|
94
|
+
// Check if session already exists
|
|
95
|
+
if (this.session && this.session.status !== 'stopped') {
|
|
96
|
+
throw new Error('Session already exists');
|
|
97
|
+
}
|
|
98
|
+
const { sandboxId, config = {} } = options;
|
|
99
|
+
const now = new Date();
|
|
100
|
+
// Create the underlying sandbox
|
|
101
|
+
this.sandbox = getSandbox(this.env.Sandbox, sandboxId, 'sandbox.do', {
|
|
102
|
+
sleepAfter: config.sleepAfter ?? '10m',
|
|
103
|
+
keepAlive: config.keepAlive ?? false,
|
|
104
|
+
normalizeId: config.normalizeId ?? true,
|
|
105
|
+
});
|
|
106
|
+
// Create session state
|
|
107
|
+
this.session = {
|
|
108
|
+
status: 'running',
|
|
109
|
+
sandboxId,
|
|
110
|
+
config,
|
|
111
|
+
createdAt: now,
|
|
112
|
+
lastActivityAt: now,
|
|
113
|
+
};
|
|
114
|
+
// Update legacy fields for backward compatibility
|
|
115
|
+
this.legacySessionId = sandboxId;
|
|
116
|
+
this.legacyCreatedAt = now.toISOString();
|
|
117
|
+
this.legacySessionStatus = 'running';
|
|
118
|
+
// Persist to storage
|
|
119
|
+
await this.persistSession();
|
|
120
|
+
// Schedule timeout alarm if configured
|
|
121
|
+
if (config.timeoutMs) {
|
|
122
|
+
await this.scheduleTimeout(config.timeoutMs);
|
|
123
|
+
}
|
|
124
|
+
// Emit lifecycle event
|
|
125
|
+
await this.emitEvent('sandbox.created', {
|
|
126
|
+
sandboxId,
|
|
127
|
+
config,
|
|
128
|
+
});
|
|
129
|
+
return this.session;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Destroy the sandbox session
|
|
133
|
+
*/
|
|
134
|
+
async destroy() {
|
|
135
|
+
if (!this.session || !this.sandbox) {
|
|
136
|
+
throw new Error('No active session');
|
|
137
|
+
}
|
|
138
|
+
const { sandboxId } = this.session;
|
|
139
|
+
// Destroy the underlying sandbox
|
|
140
|
+
await this.sandbox.destroy();
|
|
141
|
+
// Update session status
|
|
142
|
+
this.session.status = 'stopped';
|
|
143
|
+
// Emit lifecycle event
|
|
144
|
+
await this.emitEvent('sandbox.destroyed', { sandboxId });
|
|
145
|
+
// Clear session from storage
|
|
146
|
+
await this.ctx.storage.delete('session');
|
|
147
|
+
// Cancel any scheduled alarms
|
|
148
|
+
await this.ctx.storage.deleteAlarm();
|
|
149
|
+
// Clear in-memory state
|
|
150
|
+
this.session = null;
|
|
151
|
+
this.sandbox = null;
|
|
152
|
+
this.legacySessionId = null;
|
|
153
|
+
this.legacySessionStatus = 'stopped';
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Get the current session state
|
|
157
|
+
*/
|
|
158
|
+
async getState() {
|
|
159
|
+
// Try to load from storage if not in memory
|
|
160
|
+
if (!this.session) {
|
|
161
|
+
await this.loadSession();
|
|
162
|
+
}
|
|
163
|
+
return this.session;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Execute a command in the sandbox
|
|
167
|
+
*/
|
|
168
|
+
async exec(command) {
|
|
169
|
+
if (!this.session || !this.sandbox) {
|
|
170
|
+
throw new Error('No active session');
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
// Execute the command
|
|
174
|
+
const result = await this.sandbox.exec(command);
|
|
175
|
+
// Update activity timestamp
|
|
176
|
+
await this.updateActivity();
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
// Update session to error state
|
|
181
|
+
this.session.status = 'error';
|
|
182
|
+
this.session.error = error instanceof Error ? error.message : 'Unknown error';
|
|
183
|
+
await this.persistSession();
|
|
184
|
+
// Emit error event
|
|
185
|
+
await this.emitEvent('sandbox.error', {
|
|
186
|
+
sandboxId: this.session.sandboxId,
|
|
187
|
+
error: this.session.error,
|
|
188
|
+
});
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Handle DO alarm - checks for session timeout
|
|
194
|
+
*/
|
|
195
|
+
async alarm() {
|
|
196
|
+
// Call parent alarm handler first
|
|
197
|
+
await super.alarm();
|
|
198
|
+
if (!this.session) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const config = this.session.config;
|
|
202
|
+
const timeoutMs = config.timeoutMs;
|
|
203
|
+
if (!timeoutMs) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
// Check if session has timed out
|
|
207
|
+
const now = Date.now();
|
|
208
|
+
const lastActivity = new Date(this.session.lastActivityAt).getTime();
|
|
209
|
+
const elapsed = now - lastActivity;
|
|
210
|
+
if (elapsed >= timeoutMs) {
|
|
211
|
+
// Session has timed out - emit event and destroy
|
|
212
|
+
await this.emitEvent('sandbox.timeout', {
|
|
213
|
+
sandboxId: this.session.sandboxId,
|
|
214
|
+
elapsed,
|
|
215
|
+
timeoutMs,
|
|
216
|
+
});
|
|
217
|
+
await this.destroy();
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
// Reschedule alarm for remaining time
|
|
221
|
+
const remaining = timeoutMs - elapsed;
|
|
222
|
+
await this.scheduleTimeout(remaining);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// --------------------------------------------------------------------------
|
|
226
|
+
// Private Session Helpers
|
|
227
|
+
// --------------------------------------------------------------------------
|
|
228
|
+
/**
|
|
229
|
+
* Load session state from storage
|
|
230
|
+
*/
|
|
231
|
+
async loadSession() {
|
|
232
|
+
const stored = await this.ctx.storage.get('session');
|
|
233
|
+
if (stored) {
|
|
234
|
+
this.session = stored;
|
|
235
|
+
// Update legacy fields for backward compatibility
|
|
236
|
+
this.legacySessionId = stored.sandboxId;
|
|
237
|
+
this.legacyCreatedAt = new Date(stored.createdAt).toISOString();
|
|
238
|
+
this.legacySessionStatus = stored.status === 'error' ? 'stopped' : stored.status;
|
|
239
|
+
// Recreate sandbox instance if session is running
|
|
240
|
+
if (stored.status === 'running' && this.env.Sandbox) {
|
|
241
|
+
this.sandbox = getSandbox(this.env.Sandbox, stored.sandboxId, 'sandbox.do', stored.config);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Persist session state to storage
|
|
247
|
+
*/
|
|
248
|
+
async persistSession() {
|
|
249
|
+
if (this.session) {
|
|
250
|
+
await this.ctx.storage.put('session', this.session);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Update last activity timestamp and reschedule timeout
|
|
255
|
+
*/
|
|
256
|
+
async updateActivity() {
|
|
257
|
+
if (!this.session) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
this.session.lastActivityAt = new Date();
|
|
261
|
+
await this.persistSession();
|
|
262
|
+
// Reschedule timeout if configured
|
|
263
|
+
if (this.session.config.timeoutMs) {
|
|
264
|
+
await this.scheduleTimeout(this.session.config.timeoutMs);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Schedule a timeout alarm
|
|
269
|
+
*/
|
|
270
|
+
async scheduleTimeout(ms) {
|
|
271
|
+
const scheduledTime = Date.now() + ms;
|
|
272
|
+
await this.ctx.storage.setAlarm(scheduledTime);
|
|
273
|
+
}
|
|
274
|
+
// --------------------------------------------------------------------------
|
|
275
|
+
// Routes
|
|
276
|
+
// --------------------------------------------------------------------------
|
|
277
|
+
createRoutes() {
|
|
278
|
+
const app = new Hono();
|
|
279
|
+
// Error handler middleware
|
|
280
|
+
app.onError((err, c) => {
|
|
281
|
+
console.error('SandboxDO error:', err);
|
|
282
|
+
return c.json({ error: err.message || 'Internal server error' }, 500);
|
|
283
|
+
});
|
|
284
|
+
// Helper function to safely get JSON body
|
|
285
|
+
const getJsonBody = async (c) => {
|
|
286
|
+
try {
|
|
287
|
+
const contentType = c.req.header('content-type');
|
|
288
|
+
if (contentType?.includes('application/json')) {
|
|
289
|
+
return await c.req.json();
|
|
290
|
+
}
|
|
291
|
+
return {};
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
return {};
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
// GET /health - Health check
|
|
298
|
+
app.get('/health', (c) => {
|
|
299
|
+
return c.json({ status: 'ok', ns: this.ns, type: this.$type });
|
|
300
|
+
});
|
|
301
|
+
// --------------------------------------------------------------------------
|
|
302
|
+
// New Session Lifecycle Routes
|
|
303
|
+
// --------------------------------------------------------------------------
|
|
304
|
+
// POST /session - Create sandbox session (new API)
|
|
305
|
+
app.post('/session', async (c) => {
|
|
306
|
+
try {
|
|
307
|
+
const body = await getJsonBody(c);
|
|
308
|
+
// Use provided sandboxId or generate one
|
|
309
|
+
const options = {
|
|
310
|
+
sandboxId: body.sandboxId || crypto.randomUUID(),
|
|
311
|
+
config: body.config,
|
|
312
|
+
};
|
|
313
|
+
const result = await this.create(options);
|
|
314
|
+
return c.json(result, 201);
|
|
315
|
+
}
|
|
316
|
+
catch (err) {
|
|
317
|
+
const message = err instanceof Error ? err.message : 'Failed to create session';
|
|
318
|
+
return c.json({ error: message }, 400);
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
// DELETE /session - Destroy sandbox session (new API)
|
|
322
|
+
app.delete('/session', async (c) => {
|
|
323
|
+
try {
|
|
324
|
+
await this.destroy();
|
|
325
|
+
return c.json({ success: true });
|
|
326
|
+
}
|
|
327
|
+
catch (err) {
|
|
328
|
+
const message = err instanceof Error ? err.message : 'Failed to destroy session';
|
|
329
|
+
return c.json({ error: message }, 400);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
// GET /session/state - Get session state (new API)
|
|
333
|
+
app.get('/session/state', async (c) => {
|
|
334
|
+
const state = await this.getState();
|
|
335
|
+
if (!state) {
|
|
336
|
+
return c.json({ error: 'No active session' }, 404);
|
|
337
|
+
}
|
|
338
|
+
return c.json(state);
|
|
339
|
+
});
|
|
340
|
+
// --------------------------------------------------------------------------
|
|
341
|
+
// Legacy Routes (backward compatibility)
|
|
342
|
+
// --------------------------------------------------------------------------
|
|
343
|
+
// POST /create - Create sandbox session (legacy)
|
|
344
|
+
app.post('/create', async (c) => {
|
|
345
|
+
if (this.sandbox !== null) {
|
|
346
|
+
return c.json({ error: 'Session already exists' }, 409);
|
|
347
|
+
}
|
|
348
|
+
const body = await getJsonBody(c);
|
|
349
|
+
const config = {
|
|
350
|
+
sleepAfter: body.sleepAfter,
|
|
351
|
+
keepAlive: body.keepAlive,
|
|
352
|
+
};
|
|
353
|
+
try {
|
|
354
|
+
const sandboxId = crypto.randomUUID();
|
|
355
|
+
const hostname = new URL(c.req.url).hostname;
|
|
356
|
+
this.sandbox = getSandbox(this.env.Sandbox, sandboxId, hostname, config);
|
|
357
|
+
this.legacySessionId = sandboxId;
|
|
358
|
+
this.legacyCreatedAt = new Date().toISOString();
|
|
359
|
+
this.legacySessionStatus = 'running';
|
|
360
|
+
// Also create new session state
|
|
361
|
+
this.session = {
|
|
362
|
+
status: 'running',
|
|
363
|
+
sandboxId,
|
|
364
|
+
config,
|
|
365
|
+
createdAt: new Date(),
|
|
366
|
+
lastActivityAt: new Date(),
|
|
367
|
+
};
|
|
368
|
+
await this.persistSession();
|
|
369
|
+
return c.json({
|
|
370
|
+
sessionId: sandboxId,
|
|
371
|
+
status: 'created',
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
catch (err) {
|
|
375
|
+
this.sandbox = null;
|
|
376
|
+
this.legacySessionId = null;
|
|
377
|
+
throw err;
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
// POST /exec - Execute command (uses new API internally)
|
|
381
|
+
app.post('/exec', async (c) => {
|
|
382
|
+
if (!this.sandbox) {
|
|
383
|
+
return c.json({ error: 'No active session' }, 400);
|
|
384
|
+
}
|
|
385
|
+
const body = await getJsonBody(c);
|
|
386
|
+
if (!body.command) {
|
|
387
|
+
return c.json({ error: 'Missing required field: command' }, 400);
|
|
388
|
+
}
|
|
389
|
+
try {
|
|
390
|
+
const result = await this.exec(body.command);
|
|
391
|
+
return c.json(result);
|
|
392
|
+
}
|
|
393
|
+
catch (err) {
|
|
394
|
+
const message = err instanceof Error ? err.message : 'Execution failed';
|
|
395
|
+
return c.json({ error: message }, 500);
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
// POST /exec/stream - Execute command with streaming
|
|
399
|
+
app.post('/exec/stream', async (c) => {
|
|
400
|
+
if (!this.sandbox) {
|
|
401
|
+
return c.json({ error: 'No active session' }, 400);
|
|
402
|
+
}
|
|
403
|
+
const body = await getJsonBody(c);
|
|
404
|
+
if (!body.command) {
|
|
405
|
+
return c.json({ error: 'Missing required field: command' }, 400);
|
|
406
|
+
}
|
|
407
|
+
try {
|
|
408
|
+
const stream = await this.sandbox.execStream(body.command);
|
|
409
|
+
return new Response(new ReadableStream({
|
|
410
|
+
async start(controller) {
|
|
411
|
+
const encoder = new TextEncoder();
|
|
412
|
+
try {
|
|
413
|
+
for await (const event of stream) {
|
|
414
|
+
const sseData = `data: ${JSON.stringify(event)}\n\n`;
|
|
415
|
+
controller.enqueue(encoder.encode(sseData));
|
|
416
|
+
}
|
|
417
|
+
controller.close();
|
|
418
|
+
}
|
|
419
|
+
catch (err) {
|
|
420
|
+
controller.error(err);
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
}), {
|
|
424
|
+
headers: {
|
|
425
|
+
'Content-Type': 'text/event-stream',
|
|
426
|
+
'Cache-Control': 'no-cache',
|
|
427
|
+
Connection: 'keep-alive',
|
|
428
|
+
},
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
catch (err) {
|
|
432
|
+
throw err;
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
// POST /file/write - Write file
|
|
436
|
+
app.post('/file/write', async (c) => {
|
|
437
|
+
if (!this.sandbox) {
|
|
438
|
+
return c.json({ error: 'No active session' }, 400);
|
|
439
|
+
}
|
|
440
|
+
const body = await getJsonBody(c);
|
|
441
|
+
if (!body.path) {
|
|
442
|
+
return c.json({ error: 'Missing required field: path' }, 400);
|
|
443
|
+
}
|
|
444
|
+
if (body.content === undefined || body.content === null) {
|
|
445
|
+
return c.json({ error: 'Missing required field: content' }, 400);
|
|
446
|
+
}
|
|
447
|
+
try {
|
|
448
|
+
await this.sandbox.writeFile(body.path, body.content, {
|
|
449
|
+
encoding: body.encoding || 'utf-8',
|
|
450
|
+
});
|
|
451
|
+
return c.json({ success: true });
|
|
452
|
+
}
|
|
453
|
+
catch (err) {
|
|
454
|
+
throw err;
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
// GET /file/read - Read file
|
|
458
|
+
app.get('/file/read', async (c) => {
|
|
459
|
+
if (!this.sandbox) {
|
|
460
|
+
return c.json({ error: 'No active session' }, 400);
|
|
461
|
+
}
|
|
462
|
+
const path = c.req.query('path');
|
|
463
|
+
if (!path) {
|
|
464
|
+
return c.json({ error: 'Missing required query parameter: path' }, 400);
|
|
465
|
+
}
|
|
466
|
+
try {
|
|
467
|
+
const result = await this.sandbox.readFile(path);
|
|
468
|
+
return c.json(result);
|
|
469
|
+
}
|
|
470
|
+
catch (err) {
|
|
471
|
+
if (err instanceof Error && err.message.includes('not found')) {
|
|
472
|
+
return c.json({ error: 'File not found' }, 404);
|
|
473
|
+
}
|
|
474
|
+
throw err;
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
// POST /port/expose - Expose port
|
|
478
|
+
app.post('/port/expose', async (c) => {
|
|
479
|
+
if (!this.sandbox) {
|
|
480
|
+
return c.json({ error: 'No active session' }, 400);
|
|
481
|
+
}
|
|
482
|
+
const body = await getJsonBody(c);
|
|
483
|
+
if (body.port === undefined || body.port === null) {
|
|
484
|
+
return c.json({ error: 'Missing required field: port' }, 400);
|
|
485
|
+
}
|
|
486
|
+
if (typeof body.port !== 'number' || body.port < 1 || body.port > 65535) {
|
|
487
|
+
return c.json({ error: 'Invalid port number' }, 400);
|
|
488
|
+
}
|
|
489
|
+
try {
|
|
490
|
+
const result = await this.sandbox.exposePort(body.port, {
|
|
491
|
+
name: body.name,
|
|
492
|
+
});
|
|
493
|
+
return c.json(result);
|
|
494
|
+
}
|
|
495
|
+
catch (err) {
|
|
496
|
+
throw err;
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
// GET /ports - List exposed ports
|
|
500
|
+
app.get('/ports', async (c) => {
|
|
501
|
+
if (!this.sandbox) {
|
|
502
|
+
return c.json({ error: 'No active session' }, 400);
|
|
503
|
+
}
|
|
504
|
+
try {
|
|
505
|
+
const ports = await this.sandbox.getExposedPorts();
|
|
506
|
+
return c.json(ports);
|
|
507
|
+
}
|
|
508
|
+
catch (err) {
|
|
509
|
+
throw err;
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
// GET /state - Get session state (legacy)
|
|
513
|
+
app.get('/state', async (c) => {
|
|
514
|
+
const state = {
|
|
515
|
+
status: this.legacySessionStatus,
|
|
516
|
+
exposedPorts: [],
|
|
517
|
+
createdAt: this.legacyCreatedAt || '',
|
|
518
|
+
};
|
|
519
|
+
if (this.sandbox && this.legacySessionStatus === 'running') {
|
|
520
|
+
try {
|
|
521
|
+
state.exposedPorts = await this.sandbox.getExposedPorts();
|
|
522
|
+
}
|
|
523
|
+
catch {
|
|
524
|
+
// Ignore errors getting ports
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return c.json(state);
|
|
528
|
+
});
|
|
529
|
+
// POST /destroy - Destroy sandbox (legacy)
|
|
530
|
+
app.post('/destroy', async (c) => {
|
|
531
|
+
if (!this.sandbox) {
|
|
532
|
+
return c.json({ error: 'No active session' }, 400);
|
|
533
|
+
}
|
|
534
|
+
try {
|
|
535
|
+
await this.sandbox.destroy();
|
|
536
|
+
this.sandbox = null;
|
|
537
|
+
this.legacySessionId = null;
|
|
538
|
+
this.legacySessionStatus = 'stopped';
|
|
539
|
+
this.session = null;
|
|
540
|
+
await this.ctx.storage.delete('session');
|
|
541
|
+
return c.json({ success: true });
|
|
542
|
+
}
|
|
543
|
+
catch (err) {
|
|
544
|
+
throw err;
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
// GET /terminal - WebSocket upgrade
|
|
548
|
+
// Note: WebSocket upgrade is handled in fetch() method, not via Hono
|
|
549
|
+
app.get('/terminal', async (c) => {
|
|
550
|
+
if (!this.sandbox) {
|
|
551
|
+
return c.json({ error: 'No active session' }, 400);
|
|
552
|
+
}
|
|
553
|
+
const upgradeHeader = c.req.header('Upgrade');
|
|
554
|
+
if (!upgradeHeader || upgradeHeader.toLowerCase() !== 'websocket') {
|
|
555
|
+
return c.json({ error: 'WebSocket upgrade required' }, 426);
|
|
556
|
+
}
|
|
557
|
+
// WebSocket handling is done in fetch() method before routing to Hono
|
|
558
|
+
// This should not be reached for valid WebSocket requests
|
|
559
|
+
return c.json({ error: 'WebSocket upgrade required' }, 426);
|
|
560
|
+
});
|
|
561
|
+
// Method not allowed handler for known routes
|
|
562
|
+
app.all('/create', (c) => c.json({ error: 'Method not allowed' }, 405));
|
|
563
|
+
app.all('/exec', (c) => c.json({ error: 'Method not allowed' }, 405));
|
|
564
|
+
app.all('/exec/stream', (c) => c.json({ error: 'Method not allowed' }, 405));
|
|
565
|
+
app.all('/file/write', (c) => c.json({ error: 'Method not allowed' }, 405));
|
|
566
|
+
app.all('/file/read', (c) => c.json({ error: 'Method not allowed' }, 405));
|
|
567
|
+
app.all('/port/expose', (c) => c.json({ error: 'Method not allowed' }, 405));
|
|
568
|
+
app.all('/ports', (c) => c.json({ error: 'Method not allowed' }, 405));
|
|
569
|
+
app.all('/destroy', (c) => c.json({ error: 'Method not allowed' }, 405));
|
|
570
|
+
app.all('/terminal', (c) => c.json({ error: 'Method not allowed' }, 405));
|
|
571
|
+
// 404 handler
|
|
572
|
+
app.notFound((c) => c.json({ error: 'Not found' }, 404));
|
|
573
|
+
return app;
|
|
574
|
+
}
|
|
575
|
+
// --------------------------------------------------------------------------
|
|
576
|
+
// Fetch Handler
|
|
577
|
+
// --------------------------------------------------------------------------
|
|
578
|
+
async fetch(request) {
|
|
579
|
+
// Check for WebSocket upgrade on /terminal path
|
|
580
|
+
const url = new URL(request.url);
|
|
581
|
+
if (url.pathname === '/terminal' && request.headers.get('Upgrade')?.toLowerCase() === 'websocket') {
|
|
582
|
+
return this.handleTerminalWebSocket(request);
|
|
583
|
+
}
|
|
584
|
+
return this.app.fetch(request, this.env);
|
|
585
|
+
}
|
|
586
|
+
// --------------------------------------------------------------------------
|
|
587
|
+
// Terminal WebSocket Handling
|
|
588
|
+
// --------------------------------------------------------------------------
|
|
589
|
+
/**
|
|
590
|
+
* Handle WebSocket upgrade for terminal connections
|
|
591
|
+
*/
|
|
592
|
+
handleTerminalWebSocket(request) {
|
|
593
|
+
if (!this.sandbox) {
|
|
594
|
+
return new Response(JSON.stringify({ error: 'No active session' }), {
|
|
595
|
+
status: 400,
|
|
596
|
+
headers: { 'Content-Type': 'application/json' },
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
// Create WebSocket pair
|
|
600
|
+
const pair = new WebSocketPair();
|
|
601
|
+
const [client, server] = Object.values(pair);
|
|
602
|
+
// Accept the server socket
|
|
603
|
+
server.accept();
|
|
604
|
+
// Generate terminal session ID
|
|
605
|
+
const terminalSessionId = crypto.randomUUID();
|
|
606
|
+
// Get initial dimensions from query params
|
|
607
|
+
const url = new URL(request.url);
|
|
608
|
+
const cols = parseInt(url.searchParams.get('cols') || '80', 10);
|
|
609
|
+
const rows = parseInt(url.searchParams.get('rows') || '24', 10);
|
|
610
|
+
// Create terminal session
|
|
611
|
+
const session = {
|
|
612
|
+
sessionId: terminalSessionId,
|
|
613
|
+
clients: new Set([server]),
|
|
614
|
+
outputBuffer: new RingBuffer(64 * 1024), // 64KB buffer
|
|
615
|
+
cols: Math.max(1, cols),
|
|
616
|
+
rows: Math.max(1, rows),
|
|
617
|
+
};
|
|
618
|
+
this.terminalSessions.set(terminalSessionId, session);
|
|
619
|
+
// Send connected message
|
|
620
|
+
server.send(JSON.stringify({
|
|
621
|
+
type: 'connected',
|
|
622
|
+
sessionId: terminalSessionId,
|
|
623
|
+
}));
|
|
624
|
+
// Send buffered output for reconnection (if any)
|
|
625
|
+
const bufferedOutput = session.outputBuffer.getAll();
|
|
626
|
+
if (bufferedOutput) {
|
|
627
|
+
server.send(JSON.stringify({
|
|
628
|
+
type: 'output',
|
|
629
|
+
data: bufferedOutput,
|
|
630
|
+
}));
|
|
631
|
+
}
|
|
632
|
+
// Handle incoming messages
|
|
633
|
+
server.addEventListener('message', async (event) => {
|
|
634
|
+
try {
|
|
635
|
+
const msg = JSON.parse(event.data);
|
|
636
|
+
await this.handleTerminalMessage(session, server, msg);
|
|
637
|
+
}
|
|
638
|
+
catch (e) {
|
|
639
|
+
server.send(JSON.stringify({
|
|
640
|
+
type: 'error',
|
|
641
|
+
data: `\x1b[31mError: ${e.message}\x1b[0m`,
|
|
642
|
+
}));
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
// Handle close
|
|
646
|
+
server.addEventListener('close', () => {
|
|
647
|
+
session.clients.delete(server);
|
|
648
|
+
// Don't destroy session on disconnect - keep for reconnection
|
|
649
|
+
});
|
|
650
|
+
// Handle error
|
|
651
|
+
server.addEventListener('error', () => {
|
|
652
|
+
session.clients.delete(server);
|
|
653
|
+
});
|
|
654
|
+
// Return WebSocket upgrade response (Cloudflare Workers specific)
|
|
655
|
+
return new Response(null, {
|
|
656
|
+
status: 101,
|
|
657
|
+
webSocket: client,
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Handle incoming terminal WebSocket message
|
|
662
|
+
*/
|
|
663
|
+
async handleTerminalMessage(session, client, msg) {
|
|
664
|
+
switch (msg.type) {
|
|
665
|
+
case 'input':
|
|
666
|
+
// Input is handled by exec/execStream
|
|
667
|
+
// In a full PTY implementation, this would go to stdin
|
|
668
|
+
break;
|
|
669
|
+
case 'execute':
|
|
670
|
+
if (msg.command) {
|
|
671
|
+
await this.executeTerminalCommand(session, msg.command);
|
|
672
|
+
}
|
|
673
|
+
break;
|
|
674
|
+
case 'resize':
|
|
675
|
+
if (msg.cols && msg.rows && msg.cols > 0 && msg.rows > 0) {
|
|
676
|
+
session.cols = msg.cols;
|
|
677
|
+
session.rows = msg.rows;
|
|
678
|
+
// In real implementation, would send SIGWINCH to process
|
|
679
|
+
}
|
|
680
|
+
break;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Execute a command in the sandbox and stream output to terminal clients
|
|
685
|
+
*/
|
|
686
|
+
async executeTerminalCommand(session, command) {
|
|
687
|
+
if (!this.sandbox) {
|
|
688
|
+
this.broadcastToTerminal(session, {
|
|
689
|
+
type: 'error',
|
|
690
|
+
data: '\x1b[31mNo active sandbox session\x1b[0m',
|
|
691
|
+
});
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
try {
|
|
695
|
+
// Use execStream for streaming output
|
|
696
|
+
const stream = await this.sandbox.execStream(command);
|
|
697
|
+
for await (const event of stream) {
|
|
698
|
+
let message;
|
|
699
|
+
switch (event.type) {
|
|
700
|
+
case 'stdout':
|
|
701
|
+
message = { type: 'output', data: event.data };
|
|
702
|
+
// Buffer output for reconnection
|
|
703
|
+
if (event.data) {
|
|
704
|
+
session.outputBuffer.push(event.data);
|
|
705
|
+
}
|
|
706
|
+
break;
|
|
707
|
+
case 'stderr':
|
|
708
|
+
// Include ANSI color codes for errors (red)
|
|
709
|
+
const errorData = `\x1b[31m${event.data}\x1b[0m`;
|
|
710
|
+
message = { type: 'error', data: errorData };
|
|
711
|
+
// Buffer error output too
|
|
712
|
+
if (event.data) {
|
|
713
|
+
session.outputBuffer.push(errorData);
|
|
714
|
+
}
|
|
715
|
+
break;
|
|
716
|
+
case 'complete':
|
|
717
|
+
message = { type: 'exit', code: event.exitCode ?? 0 };
|
|
718
|
+
break;
|
|
719
|
+
case 'error':
|
|
720
|
+
const errMessage = `\x1b[31m${event.message}\x1b[0m`;
|
|
721
|
+
message = { type: 'error', data: errMessage };
|
|
722
|
+
break;
|
|
723
|
+
default:
|
|
724
|
+
continue;
|
|
725
|
+
}
|
|
726
|
+
// Broadcast to all connected clients
|
|
727
|
+
this.broadcastToTerminal(session, message);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
catch (error) {
|
|
731
|
+
this.broadcastToTerminal(session, {
|
|
732
|
+
type: 'error',
|
|
733
|
+
data: `\x1b[31mExecution error: ${error.message}\x1b[0m`,
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Broadcast message to all clients in a terminal session
|
|
739
|
+
*/
|
|
740
|
+
broadcastToTerminal(session, message) {
|
|
741
|
+
const data = JSON.stringify(message);
|
|
742
|
+
for (const client of session.clients) {
|
|
743
|
+
try {
|
|
744
|
+
client.send(data);
|
|
745
|
+
}
|
|
746
|
+
catch {
|
|
747
|
+
// Client disconnected, will be removed on close event
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Get terminal session by ID (for testing)
|
|
753
|
+
*/
|
|
754
|
+
getTerminalSession(sessionId) {
|
|
755
|
+
return this.terminalSessions.get(sessionId);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
export default SandboxDO;
|
|
759
|
+
//# sourceMappingURL=SandboxDO.js.map
|