@elie-laloum/outpost 3.0.0 → 4.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/CHANGELOG.md +32 -0
- package/README.md +5 -3
- package/SECURITY.md +3 -1
- package/dist/adapters/agents/codex-adapter.js +2 -0
- package/dist/adapters/agents/codex-adapter.js.map +1 -1
- package/dist/adapters/agents/codex-provider.d.ts +2 -0
- package/dist/adapters/agents/codex-provider.js +32 -0
- package/dist/adapters/agents/codex-provider.js.map +1 -0
- package/dist/adapters/agents/codex-request.js +2 -1
- package/dist/adapters/agents/codex-request.js.map +1 -1
- package/dist/adapters/agents/gemini-adapter.d.ts +3 -0
- package/dist/adapters/agents/gemini-adapter.js +15 -0
- package/dist/adapters/agents/gemini-adapter.js.map +1 -0
- package/dist/adapters/agents/gemini-diagnostics.d.ts +2 -0
- package/dist/adapters/agents/gemini-diagnostics.js +15 -0
- package/dist/adapters/agents/gemini-diagnostics.js.map +1 -0
- package/dist/adapters/agents/gemini-events.d.ts +2 -0
- package/dist/adapters/agents/gemini-events.js +50 -0
- package/dist/adapters/agents/gemini-events.js.map +1 -0
- package/dist/adapters/agents/gemini-request.d.ts +4 -0
- package/dist/adapters/agents/gemini-request.js +23 -0
- package/dist/adapters/agents/gemini-request.js.map +1 -0
- package/dist/adapters/agents/gemini.types.d.ts +6 -0
- package/dist/adapters/agents/gemini.types.js +2 -0
- package/dist/adapters/agents/gemini.types.js.map +1 -0
- package/dist/adapters/agents/protocol-fixtures.constants.d.ts +1 -1
- package/dist/adapters/agents/protocol-fixtures.constants.js +37 -0
- package/dist/adapters/agents/protocol-fixtures.constants.js.map +1 -1
- package/dist/adapters/agents/settings.types.d.ts +5 -0
- package/dist/adapters/agents/settings.types.js.map +1 -1
- package/dist/application/agent-bootstrap.constants.d.ts +1 -0
- package/dist/application/agent-bootstrap.constants.js +1 -0
- package/dist/application/agent-bootstrap.constants.js.map +1 -1
- package/dist/application/agent-bootstrap.js +6 -2
- package/dist/application/agent-bootstrap.js.map +1 -1
- package/dist/application/agent-output.js +9 -2
- package/dist/application/agent-output.js.map +1 -1
- package/dist/application/artifact-tasks.d.ts +5 -0
- package/dist/application/artifact-tasks.js +31 -0
- package/dist/application/artifact-tasks.js.map +1 -0
- package/dist/application/artifact-tasks.types.d.ts +8 -0
- package/dist/application/artifact-tasks.types.js +2 -0
- package/dist/application/artifact-tasks.types.js.map +1 -0
- package/dist/application/dispatch-validation.js +2 -0
- package/dist/application/dispatch-validation.js.map +1 -1
- package/dist/application/doctor-agent.constants.d.ts +2 -0
- package/dist/application/doctor-agent.constants.js +2 -0
- package/dist/application/doctor-agent.constants.js.map +1 -1
- package/dist/application/doctor-agent.js +1 -1
- package/dist/application/doctor-agent.js.map +1 -1
- package/dist/application/doctor-protocol.js +2 -1
- package/dist/application/doctor-protocol.js.map +1 -1
- package/dist/application/doctor.constants.js +1 -1
- package/dist/application/doctor.constants.js.map +1 -1
- package/dist/application/doctor.types.d.ts +1 -1
- package/dist/application/doctor.types.js.map +1 -1
- package/dist/application/outpost.types.d.ts +2 -0
- package/dist/application/outpost.types.js.map +1 -1
- package/dist/application/queue-worker.d.ts +2 -0
- package/dist/application/queue-worker.js +75 -0
- package/dist/application/queue-worker.js.map +1 -0
- package/dist/application/queue-worker.types.d.ts +15 -0
- package/dist/application/queue-worker.types.js +2 -0
- package/dist/application/queue-worker.types.js.map +1 -0
- package/dist/application/queued-task.d.ts +3 -0
- package/dist/application/queued-task.js +56 -0
- package/dist/application/queued-task.js.map +1 -0
- package/dist/application/queued-task.types.d.ts +11 -0
- package/dist/application/queued-task.types.js +2 -0
- package/dist/application/queued-task.types.js.map +1 -0
- package/dist/application/recovery-inspection.js +5 -0
- package/dist/application/recovery-inspection.js.map +1 -1
- package/dist/application/recovery-inspection.types.d.ts +3 -0
- package/dist/application/recovery-inspection.types.js.map +1 -1
- package/dist/application/recovery-restore-snapshot.d.ts +2 -0
- package/dist/application/recovery-restore-snapshot.js +57 -0
- package/dist/application/recovery-restore-snapshot.js.map +1 -0
- package/dist/application/recovery-restore.d.ts +3 -0
- package/dist/application/recovery-restore.js +161 -0
- package/dist/application/recovery-restore.js.map +1 -0
- package/dist/application/recovery-restore.types.d.ts +28 -0
- package/dist/application/recovery-restore.types.js +2 -0
- package/dist/application/recovery-restore.types.js.map +1 -0
- package/dist/application/recovery-retention.js +5 -0
- package/dist/application/recovery-retention.js.map +1 -1
- package/dist/application/recovery-verification.d.ts +2 -1
- package/dist/application/recovery-verification.js +1 -1
- package/dist/application/recovery-verification.js.map +1 -1
- package/dist/application/remote-apply.js +6 -0
- package/dist/application/remote-apply.js.map +1 -1
- package/dist/application/remote-download.js +2 -2
- package/dist/application/remote-download.js.map +1 -1
- package/dist/application/remote-history.d.ts +6 -0
- package/dist/application/remote-history.js +114 -0
- package/dist/application/remote-history.js.map +1 -0
- package/dist/application/remote-upload.d.ts +2 -0
- package/dist/application/remote-upload.js +17 -0
- package/dist/application/remote-upload.js.map +1 -0
- package/dist/application/remote-validation.js +20 -28
- package/dist/application/remote-validation.js.map +1 -1
- package/dist/application/remote-workspace.js +4 -10
- package/dist/application/remote-workspace.js.map +1 -1
- package/dist/application/sandbox-activity.d.ts +3 -0
- package/dist/application/sandbox-activity.js +25 -0
- package/dist/application/sandbox-activity.js.map +1 -0
- package/dist/application/sandbox-provision.js +55 -10
- package/dist/application/sandbox-provision.js.map +1 -1
- package/dist/application/sandbox-session.types.d.ts +2 -0
- package/dist/application/sandbox-session.types.js.map +1 -1
- package/dist/application/sandbox.js +23 -11
- package/dist/application/sandbox.js.map +1 -1
- package/dist/application/speculation-host.d.ts +2 -0
- package/dist/application/speculation-host.js +30 -0
- package/dist/application/speculation-host.js.map +1 -0
- package/dist/application/speculation.constants.d.ts +4 -0
- package/dist/application/speculation.constants.js +2 -0
- package/dist/application/speculation.constants.js.map +1 -0
- package/dist/application/speculation.d.ts +2 -0
- package/dist/application/speculation.js +166 -0
- package/dist/application/speculation.js.map +1 -0
- package/dist/application/speculation.types.d.ts +56 -0
- package/dist/application/speculation.types.js +2 -0
- package/dist/application/speculation.types.js.map +1 -0
- package/dist/application/storage-reservation.d.ts +3 -0
- package/dist/application/storage-reservation.js +10 -0
- package/dist/application/storage-reservation.js.map +1 -0
- package/dist/application/storage-reservation.types.d.ts +4 -0
- package/dist/application/storage-reservation.types.js +2 -0
- package/dist/application/storage-reservation.types.js.map +1 -0
- package/dist/application/task-usage.d.ts +1 -1
- package/dist/application/task-usage.js.map +1 -1
- package/dist/application/tasks.js +1 -1
- package/dist/application/tasks.js.map +1 -1
- package/dist/application/tasks.types.d.ts +4 -3
- package/dist/application/tasks.types.js.map +1 -1
- package/dist/application/workspace-allocation.d.ts +3 -0
- package/dist/application/workspace-allocation.js +34 -0
- package/dist/application/workspace-allocation.js.map +1 -0
- package/dist/application/workspace.js +2 -2
- package/dist/application/workspace.js.map +1 -1
- package/dist/cli/commands.js +55 -18
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/doctor-command.js +1 -1
- package/dist/cli/doctor-command.js.map +1 -1
- package/dist/cli/init-authentication.constants.d.ts +13 -0
- package/dist/cli/init-authentication.constants.js +10 -0
- package/dist/cli/init-authentication.constants.js.map +1 -0
- package/dist/cli/init-authentication.d.ts +4 -0
- package/dist/cli/init-authentication.js +43 -0
- package/dist/cli/init-authentication.js.map +1 -0
- package/dist/cli/init-command.js +74 -15
- package/dist/cli/init-command.js.map +1 -1
- package/dist/cli/main.constants.d.ts +111 -2
- package/dist/cli/main.constants.js +148 -42
- package/dist/cli/main.constants.js.map +1 -1
- package/dist/cli/recovery-command.js +28 -4
- package/dist/cli/recovery-command.js.map +1 -1
- package/dist/cli/recovery-restore-command.d.ts +2 -0
- package/dist/cli/recovery-restore-command.js +34 -0
- package/dist/cli/recovery-restore-command.js.map +1 -0
- package/dist/cli/scaffold-files.js +3 -2
- package/dist/cli/scaffold-files.js.map +1 -1
- package/dist/cli/scaffold-validation.js +20 -1
- package/dist/cli/scaffold-validation.js.map +1 -1
- package/dist/cli/scaffold.constants.js +2 -2
- package/dist/cli/scaffold.constants.js.map +1 -1
- package/dist/cli/scaffold.js +13 -0
- package/dist/cli/scaffold.js.map +1 -1
- package/dist/cli/scaffold.types.d.ts +4 -1
- package/dist/cli/scaffold.types.js.map +1 -1
- package/dist/cli/starters.js +9 -2
- package/dist/cli/starters.js.map +1 -1
- package/dist/domain/agent.types.d.ts +2 -0
- package/dist/domain/agent.types.js.map +1 -1
- package/dist/domain/artifact-reference.d.ts +4 -0
- package/dist/domain/artifact-reference.js +90 -0
- package/dist/domain/artifact-reference.js.map +1 -0
- package/dist/domain/artifact.constants.d.ts +2 -0
- package/dist/domain/artifact.constants.js +3 -0
- package/dist/domain/artifact.constants.js.map +1 -0
- package/dist/domain/artifact.d.ts +7 -0
- package/dist/domain/artifact.js +104 -0
- package/dist/domain/artifact.js.map +1 -0
- package/dist/domain/artifact.types.d.ts +44 -0
- package/dist/domain/artifact.types.js +2 -0
- package/dist/domain/artifact.types.js.map +1 -0
- package/dist/domain/egress.constants.d.ts +1 -0
- package/dist/domain/egress.constants.js +7 -0
- package/dist/domain/egress.constants.js.map +1 -0
- package/dist/domain/egress.d.ts +2 -0
- package/dist/domain/egress.js +48 -0
- package/dist/domain/egress.js.map +1 -0
- package/dist/domain/egress.types.d.ts +8 -0
- package/dist/domain/egress.types.js +2 -0
- package/dist/domain/egress.types.js.map +1 -0
- package/dist/domain/sandbox.types.d.ts +1 -0
- package/dist/domain/sandbox.types.js.map +1 -1
- package/dist/domain/task-queue.constants.d.ts +8 -0
- package/dist/domain/task-queue.constants.js +9 -0
- package/dist/domain/task-queue.constants.js.map +1 -0
- package/dist/domain/task-queue.d.ts +11 -0
- package/dist/domain/task-queue.js +105 -0
- package/dist/domain/task-queue.js.map +1 -0
- package/dist/domain/task-queue.types.d.ts +41 -0
- package/dist/domain/task-queue.types.js +2 -0
- package/dist/domain/task-queue.types.js.map +1 -0
- package/dist/domain/workflow/budget.d.ts +2 -2
- package/dist/domain/workflow/budget.js +5 -3
- package/dist/domain/workflow/budget.js.map +1 -1
- package/dist/domain/workflow/checkpoint-validation.d.ts +3 -0
- package/dist/domain/workflow/checkpoint-validation.js +81 -0
- package/dist/domain/workflow/checkpoint-validation.js.map +1 -0
- package/dist/domain/workflow/checkpoint-value.d.ts +2 -0
- package/dist/domain/workflow/checkpoint-value.js +49 -0
- package/dist/domain/workflow/checkpoint-value.js.map +1 -0
- package/dist/domain/workflow/checkpoint.d.ts +3 -0
- package/dist/domain/workflow/checkpoint.js +70 -0
- package/dist/domain/workflow/checkpoint.js.map +1 -0
- package/dist/domain/workflow/checkpoint.types.d.ts +40 -0
- package/dist/domain/workflow/checkpoint.types.js +2 -0
- package/dist/domain/workflow/checkpoint.types.js.map +1 -0
- package/dist/domain/workflow/gate-validation.d.ts +4 -0
- package/dist/domain/workflow/gate-validation.js +71 -0
- package/dist/domain/workflow/gate-validation.js.map +1 -0
- package/dist/domain/workflow/gates.constants.d.ts +4 -0
- package/dist/domain/workflow/gates.constants.js +5 -0
- package/dist/domain/workflow/gates.constants.js.map +1 -0
- package/dist/domain/workflow/gates.d.ts +7 -0
- package/dist/domain/workflow/gates.js +85 -0
- package/dist/domain/workflow/gates.js.map +1 -0
- package/dist/domain/workflow/gates.types.d.ts +27 -0
- package/dist/domain/workflow/gates.types.js +2 -0
- package/dist/domain/workflow/gates.types.js.map +1 -0
- package/dist/domain/workflow/task-runner.js +14 -2
- package/dist/domain/workflow/task-runner.js.map +1 -1
- package/dist/domain/workflow/usage-receipt.constants.d.ts +2 -0
- package/dist/domain/workflow/usage-receipt.constants.js +3 -0
- package/dist/domain/workflow/usage-receipt.constants.js.map +1 -0
- package/dist/domain/workflow/usage-receipt.d.ts +2 -0
- package/dist/domain/workflow/usage-receipt.js +18 -0
- package/dist/domain/workflow/usage-receipt.js.map +1 -0
- package/dist/domain/workflow/validation.js +6 -0
- package/dist/domain/workflow/validation.js.map +1 -1
- package/dist/domain/workflow/workflow-scheduler.js +65 -32
- package/dist/domain/workflow/workflow-scheduler.js.map +1 -1
- package/dist/domain/workflow/workflow-state.d.ts +2 -1
- package/dist/domain/workflow/workflow-state.js +91 -16
- package/dist/domain/workflow/workflow-state.js.map +1 -1
- package/dist/domain/workflow.types.d.ts +13 -2
- package/dist/domain/workflow.types.js.map +1 -1
- package/dist/index.d.ts +32 -2
- package/dist/index.js +14 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/artifact-store.constants.d.ts +1 -0
- package/dist/infrastructure/artifact-store.constants.js +2 -0
- package/dist/infrastructure/artifact-store.constants.js.map +1 -0
- package/dist/infrastructure/artifact-store.d.ts +3 -0
- package/dist/infrastructure/artifact-store.js +100 -0
- package/dist/infrastructure/artifact-store.js.map +1 -0
- package/dist/infrastructure/artifact-store.types.d.ts +4 -0
- package/dist/infrastructure/artifact-store.types.js +2 -0
- package/dist/infrastructure/artifact-store.types.js.map +1 -0
- package/dist/infrastructure/file-manifest.d.ts +1 -1
- package/dist/infrastructure/file-manifest.js +3 -2
- package/dist/infrastructure/file-manifest.js.map +1 -1
- package/dist/infrastructure/git/verification-command.d.ts +1 -1
- package/dist/infrastructure/git/verification-command.js +3 -2
- package/dist/infrastructure/git/verification-command.js.map +1 -1
- package/dist/infrastructure/opentelemetry.js +1 -1
- package/dist/infrastructure/opentelemetry.js.map +1 -1
- package/dist/infrastructure/resource-activity-inspection.d.ts +2 -0
- package/dist/infrastructure/resource-activity-inspection.js +152 -0
- package/dist/infrastructure/resource-activity-inspection.js.map +1 -0
- package/dist/infrastructure/resource-activity.constants.d.ts +8 -0
- package/dist/infrastructure/resource-activity.constants.js +26 -0
- package/dist/infrastructure/resource-activity.constants.js.map +1 -0
- package/dist/infrastructure/resource-activity.d.ts +2 -0
- package/dist/infrastructure/resource-activity.js +166 -0
- package/dist/infrastructure/resource-activity.js.map +1 -0
- package/dist/infrastructure/resource-activity.types.d.ts +53 -0
- package/dist/infrastructure/resource-activity.types.js +2 -0
- package/dist/infrastructure/resource-activity.types.js.map +1 -0
- package/dist/infrastructure/storage-mutation-lock.constants.d.ts +5 -0
- package/dist/infrastructure/storage-mutation-lock.constants.js +6 -0
- package/dist/infrastructure/storage-mutation-lock.constants.js.map +1 -0
- package/dist/infrastructure/storage-mutation-lock.d.ts +1 -0
- package/dist/infrastructure/storage-mutation-lock.js +21 -0
- package/dist/infrastructure/storage-mutation-lock.js.map +1 -0
- package/dist/infrastructure/storage-reservations.constants.d.ts +4 -0
- package/dist/infrastructure/storage-reservations.constants.js +5 -0
- package/dist/infrastructure/storage-reservations.constants.js.map +1 -0
- package/dist/infrastructure/storage-reservations.d.ts +2 -0
- package/dist/infrastructure/storage-reservations.js +150 -0
- package/dist/infrastructure/storage-reservations.js.map +1 -0
- package/dist/infrastructure/storage-reservations.types.d.ts +21 -0
- package/dist/infrastructure/storage-reservations.types.js +2 -0
- package/dist/infrastructure/storage-reservations.types.js.map +1 -0
- package/dist/infrastructure/task-queue-http.constants.d.ts +2 -0
- package/dist/infrastructure/task-queue-http.constants.js +3 -0
- package/dist/infrastructure/task-queue-http.constants.js.map +1 -0
- package/dist/infrastructure/task-queue-http.d.ts +4 -0
- package/dist/infrastructure/task-queue-http.js +158 -0
- package/dist/infrastructure/task-queue-http.js.map +1 -0
- package/dist/infrastructure/task-queue-http.types.d.ts +16 -0
- package/dist/infrastructure/task-queue-http.types.js +2 -0
- package/dist/infrastructure/task-queue-http.types.js.map +1 -0
- package/dist/infrastructure/task-queue.d.ts +2 -0
- package/dist/infrastructure/task-queue.js +134 -0
- package/dist/infrastructure/task-queue.js.map +1 -0
- package/dist/infrastructure/transfer.js +5 -0
- package/dist/infrastructure/transfer.js.map +1 -1
- package/dist/infrastructure/workflow-checkpoint.constants.d.ts +1 -0
- package/dist/infrastructure/workflow-checkpoint.constants.js +2 -0
- package/dist/infrastructure/workflow-checkpoint.constants.js.map +1 -0
- package/dist/infrastructure/workflow-checkpoint.d.ts +3 -0
- package/dist/infrastructure/workflow-checkpoint.js +77 -0
- package/dist/infrastructure/workflow-checkpoint.js.map +1 -0
- package/dist/infrastructure/workflow-checkpoint.types.d.ts +4 -0
- package/dist/infrastructure/workflow-checkpoint.types.js +2 -0
- package/dist/infrastructure/workflow-checkpoint.types.js.map +1 -0
- package/dist/providers/agents.d.ts +3 -1
- package/dist/providers/agents.js +1 -0
- package/dist/providers/agents.js.map +1 -1
- package/dist/providers/container-isolation.d.ts +2 -0
- package/dist/providers/container-isolation.js +29 -0
- package/dist/providers/container-isolation.js.map +1 -0
- package/dist/providers/container-mounts.js +7 -2
- package/dist/providers/container-mounts.js.map +1 -1
- package/dist/providers/container-network.d.ts +2 -0
- package/dist/providers/container-network.js +14 -0
- package/dist/providers/container-network.js.map +1 -0
- package/dist/providers/container-plan.js +4 -2
- package/dist/providers/container-plan.js.map +1 -1
- package/dist/providers/container.constants.d.ts +1 -0
- package/dist/providers/container.constants.js +1 -0
- package/dist/providers/container.constants.js.map +1 -1
- package/dist/providers/container.js +19 -2
- package/dist/providers/container.js.map +1 -1
- package/dist/providers/container.types.d.ts +3 -0
- package/dist/providers/container.types.js.map +1 -1
- package/dist/providers/daytona-command.constants.d.ts +2 -0
- package/dist/providers/daytona-command.constants.js +13 -0
- package/dist/providers/daytona-command.constants.js.map +1 -0
- package/dist/providers/daytona-command.js +12 -5
- package/dist/providers/daytona-command.js.map +1 -1
- package/dist/providers/daytona-output.d.ts +4 -0
- package/dist/providers/daytona-output.js +37 -0
- package/dist/providers/daytona-output.js.map +1 -0
- package/dist/providers/daytona-terminal.d.ts +3 -0
- package/dist/providers/daytona-terminal.js +130 -0
- package/dist/providers/daytona-terminal.js.map +1 -0
- package/dist/providers/daytona.js +2 -0
- package/dist/providers/daytona.js.map +1 -1
- package/dist/providers/docker.d.ts +1 -0
- package/dist/providers/docker.js.map +1 -1
- package/dist/providers/file-batches.d.ts +1 -1
- package/dist/providers/file-batches.js +9 -0
- package/dist/providers/file-batches.js.map +1 -1
- package/dist/providers/file-upload.constants.d.ts +1 -0
- package/dist/providers/file-upload.constants.js +68 -0
- package/dist/providers/file-upload.constants.js.map +1 -0
- package/dist/providers/file-upload.d.ts +2 -0
- package/dist/providers/file-upload.js +146 -0
- package/dist/providers/file-upload.js.map +1 -0
- package/dist/providers/firecracker-command.d.ts +5 -0
- package/dist/providers/firecracker-command.js +114 -0
- package/dist/providers/firecracker-command.js.map +1 -0
- package/dist/providers/firecracker-files.constants.d.ts +1 -0
- package/dist/providers/firecracker-files.constants.js +21 -0
- package/dist/providers/firecracker-files.constants.js.map +1 -0
- package/dist/providers/firecracker-files.d.ts +3 -0
- package/dist/providers/firecracker-files.js +110 -0
- package/dist/providers/firecracker-files.js.map +1 -0
- package/dist/providers/firecracker-machine.d.ts +3 -0
- package/dist/providers/firecracker-machine.js +155 -0
- package/dist/providers/firecracker-machine.js.map +1 -0
- package/dist/providers/firecracker.constants.d.ts +10 -0
- package/dist/providers/firecracker.constants.js +11 -0
- package/dist/providers/firecracker.constants.js.map +1 -0
- package/dist/providers/firecracker.d.ts +4 -0
- package/dist/providers/firecracker.js +103 -0
- package/dist/providers/firecracker.js.map +1 -0
- package/dist/providers/firecracker.types.d.ts +36 -0
- package/dist/providers/firecracker.types.js +2 -0
- package/dist/providers/firecracker.types.js.map +1 -0
- package/dist/providers/local.js +2 -1
- package/dist/providers/local.js.map +1 -1
- package/dist/providers/podman.d.ts +1 -0
- package/dist/providers/podman.js.map +1 -1
- package/dist/providers/terminal-bridge.d.ts +14 -0
- package/dist/providers/terminal-bridge.js +100 -0
- package/dist/providers/terminal-bridge.js.map +1 -0
- package/dist/providers/vercel-command.js +2 -2
- package/dist/providers/vercel-command.js.map +1 -1
- package/dist/providers/vercel-directory.d.ts +2 -0
- package/dist/providers/vercel-directory.js +7 -0
- package/dist/providers/vercel-directory.js.map +1 -0
- package/dist/providers/vercel-files.js +3 -2
- package/dist/providers/vercel-files.js.map +1 -1
- package/dist/providers/vercel-network.d.ts +2 -0
- package/dist/providers/vercel-network.js +18 -0
- package/dist/providers/vercel-network.js.map +1 -0
- package/dist/providers/vercel.d.ts +1 -0
- package/dist/providers/vercel.js +5 -1
- package/dist/providers/vercel.js.map +1 -1
- package/dist/providers/vercel.types.d.ts +2 -0
- package/dist/providers/vercel.types.js.map +1 -1
- package/dist/providers/versions.constants.d.ts +1 -0
- package/dist/providers/versions.constants.js +1 -0
- package/dist/providers/versions.constants.js.map +1 -1
- package/package.json +10 -2
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { queueHttpTimeoutMs, queueHttpMaxHeaderBytes, } from "./task-queue-http.constants.js";
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import { timingSafeEqual } from "node:crypto";
|
|
4
|
+
import { queueMaxBytes } from "../domain/task-queue.constants.js";
|
|
5
|
+
import { queueClaim, queueJob, queueLease, queueLeaseMs, queueNumber, queueObject, queueRequest, queueResult, queueString, } from "../domain/task-queue.js";
|
|
6
|
+
function tokenValue(token) {
|
|
7
|
+
if (typeof token !== "string" ||
|
|
8
|
+
token.length < 32 ||
|
|
9
|
+
token.length > 512 ||
|
|
10
|
+
/\s/.test(token))
|
|
11
|
+
throw new Error("Queue bearer token must contain 32 to 512 non-whitespace characters");
|
|
12
|
+
return `Bearer ${token}`;
|
|
13
|
+
}
|
|
14
|
+
async function message(stream) {
|
|
15
|
+
const chunks = [];
|
|
16
|
+
let size = 0;
|
|
17
|
+
for await (const chunk of stream) {
|
|
18
|
+
size += chunk.byteLength;
|
|
19
|
+
if (size > queueMaxBytes)
|
|
20
|
+
throw new Error("Queue message exceeds size limit");
|
|
21
|
+
chunks.push(chunk);
|
|
22
|
+
}
|
|
23
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
24
|
+
}
|
|
25
|
+
export async function serveTaskQueue(options) {
|
|
26
|
+
const expected = Buffer.from(tokenValue(options.token));
|
|
27
|
+
const queue = options.queue;
|
|
28
|
+
const server = createServer({
|
|
29
|
+
requestTimeout: queueHttpTimeoutMs,
|
|
30
|
+
headersTimeout: queueHttpTimeoutMs,
|
|
31
|
+
maxHeaderSize: queueHttpMaxHeaderBytes,
|
|
32
|
+
}, async (request, response) => {
|
|
33
|
+
const supplied = Buffer.from(request.headers.authorization ?? "");
|
|
34
|
+
if (supplied.length !== expected.length ||
|
|
35
|
+
!timingSafeEqual(supplied, expected)) {
|
|
36
|
+
response.writeHead(401).end();
|
|
37
|
+
request.resume();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (request.method !== "POST" || request.url !== "/queue") {
|
|
41
|
+
response.writeHead(404).end();
|
|
42
|
+
request.resume();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const data = queueObject(await message(request));
|
|
47
|
+
const operations = new Map([
|
|
48
|
+
["enqueue", () => queue.enqueue(queueRequest(data.request))],
|
|
49
|
+
["get", () => queue.get(queueString(data.id))],
|
|
50
|
+
["claim", () => queue.claim(queueClaim(data.request))],
|
|
51
|
+
[
|
|
52
|
+
"renew",
|
|
53
|
+
() => queue.renew(queueLease(data.lease), queueLeaseMs(data.leaseMs)),
|
|
54
|
+
],
|
|
55
|
+
[
|
|
56
|
+
"complete",
|
|
57
|
+
() => queue.complete(queueLease(data.lease), queueResult(data.result)),
|
|
58
|
+
],
|
|
59
|
+
[
|
|
60
|
+
"cancel",
|
|
61
|
+
() => queue.cancel(queueString(data.id), queueNumber(data.fence)),
|
|
62
|
+
],
|
|
63
|
+
]);
|
|
64
|
+
const operation = operations.get(queueString(data.operation));
|
|
65
|
+
if (!operation)
|
|
66
|
+
throw new Error("Unknown queue operation");
|
|
67
|
+
const body = JSON.stringify((await operation()) ?? null);
|
|
68
|
+
if (Buffer.byteLength(body) > queueMaxBytes)
|
|
69
|
+
throw new Error("Queue response exceeds size limit");
|
|
70
|
+
response
|
|
71
|
+
.writeHead(200, {
|
|
72
|
+
"content-type": "application/json",
|
|
73
|
+
"cache-control": "no-store",
|
|
74
|
+
})
|
|
75
|
+
.end(body);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
response.writeHead(400).end("Queue request rejected");
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
server.setTimeout(queueHttpTimeoutMs, (socket) => socket.destroy());
|
|
82
|
+
await new Promise((resolve, reject) => {
|
|
83
|
+
server.once("error", reject);
|
|
84
|
+
server.listen(options.port ?? 0, options.host ?? "127.0.0.1", resolve);
|
|
85
|
+
});
|
|
86
|
+
const address = server.address();
|
|
87
|
+
if (!address || typeof address === "string")
|
|
88
|
+
throw new Error("Queue server address unavailable");
|
|
89
|
+
const host = address.family === "IPv6" ? `[${address.address}]` : address.address;
|
|
90
|
+
return {
|
|
91
|
+
url: `http://${host}:${address.port}`,
|
|
92
|
+
close: () => new Promise((resolve, reject) => {
|
|
93
|
+
server.close((error) => (error ? reject(error) : resolve()));
|
|
94
|
+
server.closeIdleConnections();
|
|
95
|
+
}),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export function httpTaskQueue(options) {
|
|
99
|
+
const authorization = tokenValue(options.token);
|
|
100
|
+
const url = new URL(options.url);
|
|
101
|
+
if (!["http:", "https:"].includes(url.protocol) ||
|
|
102
|
+
url.username ||
|
|
103
|
+
url.password ||
|
|
104
|
+
url.search ||
|
|
105
|
+
url.hash)
|
|
106
|
+
throw new Error("Invalid queue URL");
|
|
107
|
+
const endpoint = new URL("queue", `${url.href.replace(/\/$/, "")}/`);
|
|
108
|
+
const timeoutMs = options.timeoutMs ?? queueHttpTimeoutMs;
|
|
109
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0)
|
|
110
|
+
throw new Error("Invalid queue request timeout");
|
|
111
|
+
async function call(data) {
|
|
112
|
+
const body = JSON.stringify(data);
|
|
113
|
+
if (Buffer.byteLength(body) > queueMaxBytes)
|
|
114
|
+
throw new Error("Queue message exceeds size limit");
|
|
115
|
+
const response = await fetch(endpoint, {
|
|
116
|
+
method: "POST",
|
|
117
|
+
headers: { authorization, "content-type": "application/json" },
|
|
118
|
+
body,
|
|
119
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
120
|
+
redirect: "error",
|
|
121
|
+
});
|
|
122
|
+
if (!response.ok) {
|
|
123
|
+
await response.body?.cancel();
|
|
124
|
+
throw new Error(`Queue request rejected (${response.status})`);
|
|
125
|
+
}
|
|
126
|
+
if (!response.body)
|
|
127
|
+
throw new Error("Missing queue response");
|
|
128
|
+
const value = await message(response.body);
|
|
129
|
+
return value === null ? undefined : queueJob(value);
|
|
130
|
+
}
|
|
131
|
+
async function required(data) {
|
|
132
|
+
const job = await call(data);
|
|
133
|
+
if (!job)
|
|
134
|
+
throw new Error("Missing queue job");
|
|
135
|
+
return job;
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
enqueue: (request) => required({ operation: "enqueue", request: queueRequest(request) }),
|
|
139
|
+
get: (id) => call({ operation: "get", id: queueString(id) }),
|
|
140
|
+
claim: (request) => call({ operation: "claim", request: queueClaim(request) }),
|
|
141
|
+
renew: (lease, leaseMs) => required({
|
|
142
|
+
operation: "renew",
|
|
143
|
+
lease: queueLease(lease),
|
|
144
|
+
leaseMs: queueLeaseMs(leaseMs),
|
|
145
|
+
}),
|
|
146
|
+
complete: (lease, result) => required({
|
|
147
|
+
operation: "complete",
|
|
148
|
+
lease: queueLease(lease),
|
|
149
|
+
result: queueResult(result),
|
|
150
|
+
}),
|
|
151
|
+
cancel: (id, fence) => required({
|
|
152
|
+
operation: "cancel",
|
|
153
|
+
id: queueString(id),
|
|
154
|
+
fence: queueNumber(fence),
|
|
155
|
+
}),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=task-queue-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-queue-http.js","sourceRoot":"","sources":["../../src/infrastructure/task-queue-http.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n queueHttpTimeoutMs,\n queueHttpMaxHeaderBytes,\n} from \"./task-queue-http.constants.ts\";\nimport { createServer } from \"node:http\";\nimport { timingSafeEqual } from \"node:crypto\";\nimport { queueMaxBytes } from \"../domain/task-queue.constants.ts\";\nimport {\n queueClaim,\n queueJob,\n queueLease,\n queueLeaseMs,\n queueNumber,\n queueObject,\n queueRequest,\n queueResult,\n queueString,\n} from \"../domain/task-queue.ts\";\nimport type { TaskQueue } from \"../domain/task-queue.types.ts\";\nimport type {\n QueueClientOptions,\n QueueServer,\n QueueServerOptions,\n} from \"./task-queue-http.types.ts\";\n\nfunction tokenValue(token: string): string {\n if (\n typeof token !== \"string\" ||\n token.length < 32 ||\n token.length > 512 ||\n /\\s/.test(token)\n )\n throw new Error(\n \"Queue bearer token must contain 32 to 512 non-whitespace characters\",\n );\n return `Bearer ${token}`;\n}\nasync function message(stream: AsyncIterable<Uint8Array>): Promise<unknown> {\n const chunks: Uint8Array[] = [];\n let size = 0;\n for await (const chunk of stream) {\n size += chunk.byteLength;\n if (size > queueMaxBytes)\n throw new Error(\"Queue message exceeds size limit\");\n chunks.push(chunk);\n }\n return JSON.parse(Buffer.concat(chunks).toString(\"utf8\"));\n}\nexport async function serveTaskQueue(\n options: QueueServerOptions,\n): Promise<QueueServer> {\n const expected = Buffer.from(tokenValue(options.token));\n const queue = options.queue;\n const server = createServer(\n {\n requestTimeout: queueHttpTimeoutMs,\n headersTimeout: queueHttpTimeoutMs,\n maxHeaderSize: queueHttpMaxHeaderBytes,\n },\n async (request, response) => {\n const supplied = Buffer.from(request.headers.authorization ?? \"\");\n if (\n supplied.length !== expected.length ||\n !timingSafeEqual(supplied, expected)\n ) {\n response.writeHead(401).end();\n request.resume();\n return;\n }\n if (request.method !== \"POST\" || request.url !== \"/queue\") {\n response.writeHead(404).end();\n request.resume();\n return;\n }\n try {\n const data = queueObject(await message(request));\n const operations = new Map<string, () => Promise<unknown>>([\n [\"enqueue\", () => queue.enqueue(queueRequest(data.request))],\n [\"get\", () => queue.get(queueString(data.id))],\n [\"claim\", () => queue.claim(queueClaim(data.request))],\n [\n \"renew\",\n () =>\n queue.renew(queueLease(data.lease), queueLeaseMs(data.leaseMs)),\n ],\n [\n \"complete\",\n () =>\n queue.complete(queueLease(data.lease), queueResult(data.result)),\n ],\n [\n \"cancel\",\n () => queue.cancel(queueString(data.id), queueNumber(data.fence)),\n ],\n ]);\n const operation = operations.get(queueString(data.operation));\n if (!operation) throw new Error(\"Unknown queue operation\");\n const body = JSON.stringify((await operation()) ?? null);\n if (Buffer.byteLength(body) > queueMaxBytes)\n throw new Error(\"Queue response exceeds size limit\");\n response\n .writeHead(200, {\n \"content-type\": \"application/json\",\n \"cache-control\": \"no-store\",\n })\n .end(body);\n } catch {\n response.writeHead(400).end(\"Queue request rejected\");\n }\n },\n );\n server.setTimeout(queueHttpTimeoutMs, (socket) => socket.destroy());\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(options.port ?? 0, options.host ?? \"127.0.0.1\", resolve);\n });\n const address = server.address();\n if (!address || typeof address === \"string\")\n throw new Error(\"Queue server address unavailable\");\n const host =\n address.family === \"IPv6\" ? `[${address.address}]` : address.address;\n return {\n url: `http://${host}:${address.port}`,\n close: () =>\n new Promise<void>((resolve, reject) => {\n server.close((error) => (error ? reject(error) : resolve()));\n server.closeIdleConnections();\n }),\n };\n}\nexport function httpTaskQueue(options: QueueClientOptions): TaskQueue {\n const authorization = tokenValue(options.token);\n const url = new URL(options.url);\n if (\n ![\"http:\", \"https:\"].includes(url.protocol) ||\n url.username ||\n url.password ||\n url.search ||\n url.hash\n )\n throw new Error(\"Invalid queue URL\");\n const endpoint = new URL(\"queue\", `${url.href.replace(/\\/$/, \"\")}/`);\n const timeoutMs = options.timeoutMs ?? queueHttpTimeoutMs;\n if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0)\n throw new Error(\"Invalid queue request timeout\");\n async function call(data: unknown) {\n const body = JSON.stringify(data);\n if (Buffer.byteLength(body) > queueMaxBytes)\n throw new Error(\"Queue message exceeds size limit\");\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers: { authorization, \"content-type\": \"application/json\" },\n body,\n signal: AbortSignal.timeout(timeoutMs),\n redirect: \"error\",\n });\n if (!response.ok) {\n await response.body?.cancel();\n throw new Error(`Queue request rejected (${response.status})`);\n }\n if (!response.body) throw new Error(\"Missing queue response\");\n const value = await message(response.body);\n return value === null ? undefined : queueJob(value);\n }\n async function required(data: unknown) {\n const job = await call(data);\n if (!job) throw new Error(\"Missing queue job\");\n return job;\n }\n return {\n enqueue: (request) =>\n required({ operation: \"enqueue\", request: queueRequest(request) }),\n get: (id) => call({ operation: \"get\", id: queueString(id) }),\n claim: (request) =>\n call({ operation: \"claim\", request: queueClaim(request) }),\n renew: (lease, leaseMs) =>\n required({\n operation: \"renew\",\n lease: queueLease(lease),\n leaseMs: queueLeaseMs(leaseMs),\n }),\n complete: (lease, result) =>\n required({\n operation: \"complete\",\n lease: queueLease(lease),\n result: queueResult(result),\n }),\n cancel: (id, fence) =>\n required({\n operation: \"cancel\",\n id: queueString(id),\n fence: queueNumber(fence),\n }),\n };\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TaskQueue } from "../domain/task-queue.types.ts";
|
|
2
|
+
export interface QueueServerOptions {
|
|
3
|
+
readonly queue: TaskQueue;
|
|
4
|
+
readonly token: string;
|
|
5
|
+
readonly host?: string;
|
|
6
|
+
readonly port?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface QueueServer {
|
|
9
|
+
readonly url: string;
|
|
10
|
+
close(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export interface QueueClientOptions {
|
|
13
|
+
readonly url: string;
|
|
14
|
+
readonly token: string;
|
|
15
|
+
readonly timeoutMs?: number;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-queue-http.types.js","sourceRoot":"","sources":["../../src/infrastructure/task-queue-http.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { TaskQueue } from \"../domain/task-queue.types.ts\";\nexport interface QueueServerOptions {\n readonly queue: TaskQueue;\n readonly token: string;\n readonly host?: string;\n readonly port?: number;\n}\nexport interface QueueServer {\n readonly url: string;\n close(): Promise<void>;\n}\nexport interface QueueClientOptions {\n readonly url: string;\n readonly token: string;\n readonly timeoutMs?: number;\n}\n"]}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { mkdirSync, chmodSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { queueClaim, queueJob, queueLease, queueLeaseMs, queueNumber, queueRequest, queueResult, queueString, } from "../domain/task-queue.js";
|
|
4
|
+
export async function sqliteTaskQueue(path) {
|
|
5
|
+
const { DatabaseSync } = await import("node:sqlite");
|
|
6
|
+
const file = resolve(path);
|
|
7
|
+
mkdirSync(dirname(file), { recursive: true, mode: 0o700 });
|
|
8
|
+
const db = new DatabaseSync(file);
|
|
9
|
+
chmodSync(file, 0o600);
|
|
10
|
+
db.exec("PRAGMA busy_timeout=5000; PRAGMA synchronous=FULL; CREATE TABLE IF NOT EXISTS queue_jobs (id TEXT PRIMARY KEY, body TEXT NOT NULL, status TEXT NOT NULL, handler TEXT NOT NULL, expires INTEGER, deadline INTEGER); CREATE INDEX IF NOT EXISTS queue_eligible ON queue_jobs(status, handler, expires, deadline, id)");
|
|
11
|
+
function read(id) {
|
|
12
|
+
const row = db.prepare("SELECT body FROM queue_jobs WHERE id = ?").get(id);
|
|
13
|
+
return row ? queueJob(JSON.parse(String(row.body))) : undefined;
|
|
14
|
+
}
|
|
15
|
+
function save(job) {
|
|
16
|
+
db.prepare("INSERT INTO queue_jobs(id, body, status, handler, expires, deadline) VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET body=excluded.body, status=excluded.status, handler=excluded.handler, expires=excluded.expires, deadline=excluded.deadline").run(job.id, JSON.stringify(job), job.status, job.handler, job.expires ?? null, job.deadline ?? null);
|
|
17
|
+
return job;
|
|
18
|
+
}
|
|
19
|
+
function transaction(operation) {
|
|
20
|
+
db.exec("BEGIN IMMEDIATE");
|
|
21
|
+
try {
|
|
22
|
+
const result = operation();
|
|
23
|
+
db.exec("COMMIT");
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
db.exec("ROLLBACK");
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function expire(job) {
|
|
32
|
+
if ((job.status === "pending" || job.status === "active") &&
|
|
33
|
+
job.deadline !== undefined &&
|
|
34
|
+
job.deadline <= Date.now())
|
|
35
|
+
return save({ ...job, status: "cancelled", fence: job.fence + 1 });
|
|
36
|
+
return job;
|
|
37
|
+
}
|
|
38
|
+
function required(id) {
|
|
39
|
+
const job = read(queueString(id));
|
|
40
|
+
if (!job)
|
|
41
|
+
throw new Error("Queue job does not exist");
|
|
42
|
+
return expire(job);
|
|
43
|
+
}
|
|
44
|
+
function owned(input) {
|
|
45
|
+
const lease = queueLease(input);
|
|
46
|
+
const job = required(lease.id);
|
|
47
|
+
if (job.status !== "active" ||
|
|
48
|
+
job.worker !== lease.worker ||
|
|
49
|
+
job.fence !== lease.fence ||
|
|
50
|
+
(job.expires ?? 0) <= Date.now())
|
|
51
|
+
throw new Error("Stale queue lease");
|
|
52
|
+
return job;
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
async enqueue(input) {
|
|
56
|
+
return transaction(() => {
|
|
57
|
+
const request = queueRequest(input);
|
|
58
|
+
const existing = read(request.id);
|
|
59
|
+
if (existing) {
|
|
60
|
+
if (JSON.stringify(queueRequest(existing)) !== JSON.stringify(request))
|
|
61
|
+
throw new Error("Queue identity already has a different request");
|
|
62
|
+
return expire(existing);
|
|
63
|
+
}
|
|
64
|
+
return expire(save({ ...request, status: "pending", fence: 0 }));
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
async get(id) {
|
|
68
|
+
return transaction(() => {
|
|
69
|
+
const job = read(queueString(id));
|
|
70
|
+
return job ? expire(job) : undefined;
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
async claim(input) {
|
|
74
|
+
return transaction(() => {
|
|
75
|
+
const claim = queueClaim(input);
|
|
76
|
+
const now = Date.now();
|
|
77
|
+
const placeholders = claim.handlers.map(() => "?").join(",");
|
|
78
|
+
const selected = db
|
|
79
|
+
.prepare(`SELECT id FROM queue_jobs INDEXED BY queue_eligible
|
|
80
|
+
WHERE status IN ('pending', 'active') AND handler IN (${placeholders})
|
|
81
|
+
AND (status = 'pending' OR expires <= ?)
|
|
82
|
+
AND (deadline IS NULL OR deadline > ?)
|
|
83
|
+
ORDER BY rowid LIMIT 1`)
|
|
84
|
+
.get(...claim.handlers, now, now);
|
|
85
|
+
if (!selected)
|
|
86
|
+
return undefined;
|
|
87
|
+
const job = required(String(selected.id));
|
|
88
|
+
if (job.status === "cancelled")
|
|
89
|
+
return undefined;
|
|
90
|
+
return save({
|
|
91
|
+
...job,
|
|
92
|
+
status: "active",
|
|
93
|
+
worker: claim.worker,
|
|
94
|
+
fence: job.fence + 1,
|
|
95
|
+
expires: Math.min(now + claim.leaseMs, job.deadline ?? Infinity),
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
async renew(lease, ms) {
|
|
100
|
+
return transaction(() => {
|
|
101
|
+
const job = owned(lease);
|
|
102
|
+
return save({
|
|
103
|
+
...job,
|
|
104
|
+
expires: Math.min(Date.now() + queueLeaseMs(ms), job.deadline ?? Infinity),
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
async complete(lease, input) {
|
|
109
|
+
return transaction(() => {
|
|
110
|
+
const job = owned(lease);
|
|
111
|
+
const result = queueResult(input);
|
|
112
|
+
return save({
|
|
113
|
+
...job,
|
|
114
|
+
status: result.error === undefined ? "done" : "failed",
|
|
115
|
+
result,
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
async cancel(id, fence) {
|
|
120
|
+
return transaction(() => {
|
|
121
|
+
const job = required(id);
|
|
122
|
+
if (job.fence !== queueNumber(fence))
|
|
123
|
+
throw new Error("Stale queue fence");
|
|
124
|
+
if (job.status !== "pending" && job.status !== "active")
|
|
125
|
+
return job;
|
|
126
|
+
return save({ ...job, status: "cancelled", fence: job.fence + 1 });
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
close() {
|
|
130
|
+
db.close();
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=task-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-queue.js","sourceRoot":"","sources":["../../src/infrastructure/task-queue.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdirSync, chmodSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport {\n queueClaim,\n queueJob,\n queueLease,\n queueLeaseMs,\n queueNumber,\n queueRequest,\n queueResult,\n queueString,\n} from \"../domain/task-queue.ts\";\nimport type {\n DurableTaskQueue,\n QueueJob,\n QueueLease,\n} from \"../domain/task-queue.types.ts\";\n\nexport async function sqliteTaskQueue(path: string): Promise<DurableTaskQueue> {\n const { DatabaseSync } = await import(\"node:sqlite\");\n const file = resolve(path);\n mkdirSync(dirname(file), { recursive: true, mode: 0o700 });\n const db = new DatabaseSync(file);\n chmodSync(file, 0o600);\n db.exec(\n \"PRAGMA busy_timeout=5000; PRAGMA synchronous=FULL; CREATE TABLE IF NOT EXISTS queue_jobs (id TEXT PRIMARY KEY, body TEXT NOT NULL, status TEXT NOT NULL, handler TEXT NOT NULL, expires INTEGER, deadline INTEGER); CREATE INDEX IF NOT EXISTS queue_eligible ON queue_jobs(status, handler, expires, deadline, id)\",\n );\n function read(id: string): QueueJob | undefined {\n const row = db.prepare(\"SELECT body FROM queue_jobs WHERE id = ?\").get(id);\n return row ? queueJob(JSON.parse(String(row.body))) : undefined;\n }\n function save(job: QueueJob): QueueJob {\n db.prepare(\n \"INSERT INTO queue_jobs(id, body, status, handler, expires, deadline) VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET body=excluded.body, status=excluded.status, handler=excluded.handler, expires=excluded.expires, deadline=excluded.deadline\",\n ).run(\n job.id,\n JSON.stringify(job),\n job.status,\n job.handler,\n job.expires ?? null,\n job.deadline ?? null,\n );\n return job;\n }\n function transaction<T>(operation: () => T): T {\n db.exec(\"BEGIN IMMEDIATE\");\n try {\n const result = operation();\n db.exec(\"COMMIT\");\n return result;\n } catch (error) {\n db.exec(\"ROLLBACK\");\n throw error;\n }\n }\n function expire(job: QueueJob): QueueJob {\n if (\n (job.status === \"pending\" || job.status === \"active\") &&\n job.deadline !== undefined &&\n job.deadline <= Date.now()\n )\n return save({ ...job, status: \"cancelled\", fence: job.fence + 1 });\n return job;\n }\n function required(id: string): QueueJob {\n const job = read(queueString(id));\n if (!job) throw new Error(\"Queue job does not exist\");\n return expire(job);\n }\n function owned(input: QueueLease): QueueJob {\n const lease = queueLease(input);\n const job = required(lease.id);\n if (\n job.status !== \"active\" ||\n job.worker !== lease.worker ||\n job.fence !== lease.fence ||\n (job.expires ?? 0) <= Date.now()\n )\n throw new Error(\"Stale queue lease\");\n return job;\n }\n return {\n async enqueue(input) {\n return transaction(() => {\n const request = queueRequest(input);\n const existing = read(request.id);\n if (existing) {\n if (\n JSON.stringify(queueRequest(existing)) !== JSON.stringify(request)\n )\n throw new Error(\"Queue identity already has a different request\");\n return expire(existing);\n }\n return expire(save({ ...request, status: \"pending\", fence: 0 }));\n });\n },\n async get(id) {\n return transaction(() => {\n const job = read(queueString(id));\n return job ? expire(job) : undefined;\n });\n },\n async claim(input) {\n return transaction(() => {\n const claim = queueClaim(input);\n const now = Date.now();\n const placeholders = claim.handlers.map(() => \"?\").join(\",\");\n const selected = db\n .prepare(\n `SELECT id FROM queue_jobs INDEXED BY queue_eligible\n WHERE status IN ('pending', 'active') AND handler IN (${placeholders})\n AND (status = 'pending' OR expires <= ?)\n AND (deadline IS NULL OR deadline > ?)\n ORDER BY rowid LIMIT 1`,\n )\n .get(...claim.handlers, now, now);\n if (!selected) return undefined;\n const job = required(String(selected.id));\n if (job.status === \"cancelled\") return undefined;\n return save({\n ...job,\n status: \"active\",\n worker: claim.worker,\n fence: job.fence + 1,\n expires: Math.min(now + claim.leaseMs, job.deadline ?? Infinity),\n });\n });\n },\n async renew(lease, ms) {\n return transaction(() => {\n const job = owned(lease);\n return save({\n ...job,\n expires: Math.min(\n Date.now() + queueLeaseMs(ms),\n job.deadline ?? Infinity,\n ),\n });\n });\n },\n async complete(lease, input) {\n return transaction(() => {\n const job = owned(lease);\n const result = queueResult(input);\n return save({\n ...job,\n status: result.error === undefined ? \"done\" : \"failed\",\n result,\n });\n });\n },\n async cancel(id, fence) {\n return transaction(() => {\n const job = required(id);\n if (job.fence !== queueNumber(fence))\n throw new Error(\"Stale queue fence\");\n if (job.status !== \"pending\" && job.status !== \"active\") return job;\n return save({ ...job, status: \"cancelled\", fence: job.fence + 1 });\n });\n },\n close() {\n db.close();\n },\n };\n}\n"]}
|
|
@@ -28,6 +28,11 @@ export function boundedTransfers(lease, defaults) {
|
|
|
28
28
|
...(lease.fileTransfers
|
|
29
29
|
? {
|
|
30
30
|
fileTransfers: {
|
|
31
|
+
...(lease.fileTransfers.uploadBatch
|
|
32
|
+
? {
|
|
33
|
+
uploadBatch: (source, entries, destination, options = {}) => transfer({ ...defaults, ...options }, (signal) => lease.fileTransfers.uploadBatch(source, entries, destination, { ...defaults, ...options, signal })),
|
|
34
|
+
}
|
|
35
|
+
: {}),
|
|
31
36
|
manifest: (source, paths, options = {}) => transfer({ ...defaults, ...options }, (signal) => lease.fileTransfers.manifest(source, paths, {
|
|
32
37
|
...defaults,
|
|
33
38
|
...options,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transfer.js","sourceRoot":"","sources":["../../src/infrastructure/transfer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"transfer.js","sourceRoot":"","sources":["../../src/infrastructure/transfer.ts"],"names":[],"mappings":"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","sourcesContent":["import { invariant, OutpostError } from \"../domain/errors.ts\";\nimport type {\n FileManifestEntry,\n SandboxLease,\n TransferOptions,\n} from \"../domain/sandbox.types.ts\";\nimport { interruptible } from \"./abort.ts\";\nimport { transferDefaults } from \"./transfer.constants.ts\";\n\nexport async function transfer<T>(\n options: TransferOptions,\n perform: (signal: AbortSignal) => Promise<T>,\n): Promise<T> {\n options.signal?.throwIfAborted();\n const deadlineMs = options.deadlineMs ?? transferDefaults.deadlineMs;\n invariant(\n Number.isFinite(deadlineMs) && deadlineMs > 0,\n \"Transfer deadline must be positive\",\n );\n const stop = new AbortController();\n const signal = options.signal\n ? AbortSignal.any([options.signal, stop.signal])\n : stop.signal;\n const timer = setTimeout(\n () =>\n stop.abort(\n new OutpostError(\"timeout\", \"File transfer timed out\", { deadlineMs }),\n ),\n deadlineMs,\n );\n try {\n return await interruptible(perform(signal), signal);\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport function boundedTransfers(\n lease: SandboxLease,\n defaults: TransferOptions,\n): SandboxLease {\n const copy =\n (method: \"upload\" | \"download\") =>\n (source: string, destination: string, options: TransferOptions = {}) =>\n transfer({ ...defaults, ...options }, (signal) =>\n lease[method](source, destination, { ...defaults, ...options, signal }),\n );\n return {\n ...lease,\n invoke: lease.invoke.bind(lease),\n release: lease.release.bind(lease),\n upload: copy(\"upload\"),\n download: copy(\"download\"),\n ...(lease.fileTransfers\n ? {\n fileTransfers: {\n ...(lease.fileTransfers.uploadBatch\n ? {\n uploadBatch: (\n source: string,\n entries: readonly FileManifestEntry[],\n destination: string,\n options: TransferOptions = {},\n ) =>\n transfer({ ...defaults, ...options }, (signal) =>\n lease.fileTransfers!.uploadBatch!(\n source,\n entries,\n destination,\n { ...defaults, ...options, signal },\n ),\n ),\n }\n : {}),\n manifest: (source, paths, options = {}) =>\n transfer({ ...defaults, ...options }, (signal) =>\n lease.fileTransfers!.manifest(source, paths, {\n ...defaults,\n ...options,\n signal,\n }),\n ),\n downloadBatch: (source, entries, destination, options = {}) =>\n transfer({ ...defaults, ...options }, (signal) =>\n lease.fileTransfers!.downloadBatch(\n source,\n entries,\n destination,\n { ...defaults, ...options, signal },\n ),\n ),\n },\n }\n : {}),\n };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const workflowCheckpointMaxBytes: number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-checkpoint.constants.js","sourceRoot":"","sources":["../../src/infrastructure/workflow-checkpoint.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC","sourcesContent":["export const workflowCheckpointMaxBytes = 16 * 1024 * 1024;\n"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { WorkflowCheckpointStore } from "../domain/workflow/checkpoint.types.ts";
|
|
2
|
+
import type { FileWorkflowCheckpointOptions } from "./workflow-checkpoint.types.ts";
|
|
3
|
+
export declare function fileWorkflowCheckpointStore(options: FileWorkflowCheckpointOptions): WorkflowCheckpointStore;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { readInspectionFile } from "./inspection-file.js";
|
|
2
|
+
import { workflowCheckpointMaxBytes } from "./workflow-checkpoint.constants.js";
|
|
3
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
4
|
+
import { mkdir, open, realpath, rename, rm } from "node:fs/promises";
|
|
5
|
+
import { join, resolve } from "node:path";
|
|
6
|
+
import { lock } from "./git/lock.js";
|
|
7
|
+
export function fileWorkflowCheckpointStore(options) {
|
|
8
|
+
const configuredDirectory = resolve(options.directory);
|
|
9
|
+
return {
|
|
10
|
+
async acquire(runId) {
|
|
11
|
+
if (!runId.trim())
|
|
12
|
+
throw new Error("Checkpoint runId must not be empty");
|
|
13
|
+
await mkdir(configuredDirectory, { recursive: true, mode: 0o700 });
|
|
14
|
+
const directory = await realpath(configuredDirectory);
|
|
15
|
+
const release = await lock(directory, `workflow:${runId}`);
|
|
16
|
+
const path = join(directory, `${createHash("sha256").update(runId).digest("hex")}.json`);
|
|
17
|
+
let released = false;
|
|
18
|
+
const assertOwned = () => {
|
|
19
|
+
if (released)
|
|
20
|
+
throw new Error("Checkpoint lease has been released");
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
async read() {
|
|
24
|
+
assertOwned();
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse((await readInspectionFile(path, workflowCheckpointMaxBytes)).toString("utf8"));
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
if (error &&
|
|
30
|
+
typeof error === "object" &&
|
|
31
|
+
"code" in error &&
|
|
32
|
+
error.code === "ENOENT")
|
|
33
|
+
return undefined;
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
async write(checkpoint) {
|
|
38
|
+
assertOwned();
|
|
39
|
+
const data = JSON.stringify(checkpoint);
|
|
40
|
+
if (Buffer.byteLength(data) > workflowCheckpointMaxBytes)
|
|
41
|
+
throw new Error("Workflow checkpoint exceeds 16 MiB; store large artifacts separately");
|
|
42
|
+
const temporary = `${path}.${randomUUID()}.tmp`;
|
|
43
|
+
try {
|
|
44
|
+
const file = await open(temporary, "wx", 0o600);
|
|
45
|
+
try {
|
|
46
|
+
await file.writeFile(data);
|
|
47
|
+
await file.sync();
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
await file.close();
|
|
51
|
+
}
|
|
52
|
+
await rename(temporary, path);
|
|
53
|
+
if (process.platform !== "win32") {
|
|
54
|
+
const parent = await open(directory, "r");
|
|
55
|
+
try {
|
|
56
|
+
await parent.sync();
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
await parent.close();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
await rm(temporary, { force: true });
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
async release() {
|
|
68
|
+
if (released)
|
|
69
|
+
return;
|
|
70
|
+
released = true;
|
|
71
|
+
await release();
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=workflow-checkpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-checkpoint.js","sourceRoot":"","sources":["../../src/infrastructure/workflow-checkpoint.ts"],"names":[],"mappings":"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","sourcesContent":["import { readInspectionFile } from \"./inspection-file.ts\";\nimport { workflowCheckpointMaxBytes } from \"./workflow-checkpoint.constants.ts\";\nimport { createHash, randomUUID } from \"node:crypto\";\nimport { mkdir, open, realpath, rename, rm } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport type { WorkflowCheckpointStore } from \"../domain/workflow/checkpoint.types.ts\";\nimport type { FileWorkflowCheckpointOptions } from \"./workflow-checkpoint.types.ts\";\nimport { lock } from \"./git/lock.ts\";\n\nexport function fileWorkflowCheckpointStore(\n options: FileWorkflowCheckpointOptions,\n): WorkflowCheckpointStore {\n const configuredDirectory = resolve(options.directory);\n return {\n async acquire(runId) {\n if (!runId.trim()) throw new Error(\"Checkpoint runId must not be empty\");\n await mkdir(configuredDirectory, { recursive: true, mode: 0o700 });\n const directory = await realpath(configuredDirectory);\n const release = await lock(directory, `workflow:${runId}`);\n const path = join(\n directory,\n `${createHash(\"sha256\").update(runId).digest(\"hex\")}.json`,\n );\n let released = false;\n const assertOwned = () => {\n if (released) throw new Error(\"Checkpoint lease has been released\");\n };\n return {\n async read() {\n assertOwned();\n try {\n return JSON.parse(\n (\n await readInspectionFile(path, workflowCheckpointMaxBytes)\n ).toString(\"utf8\"),\n ) as unknown;\n } catch (error) {\n if (\n error &&\n typeof error === \"object\" &&\n \"code\" in error &&\n error.code === \"ENOENT\"\n )\n return undefined;\n throw error;\n }\n },\n async write(checkpoint) {\n assertOwned();\n const data = JSON.stringify(checkpoint);\n if (Buffer.byteLength(data) > workflowCheckpointMaxBytes)\n throw new Error(\n \"Workflow checkpoint exceeds 16 MiB; store large artifacts separately\",\n );\n const temporary = `${path}.${randomUUID()}.tmp`;\n try {\n const file = await open(temporary, \"wx\", 0o600);\n try {\n await file.writeFile(data);\n await file.sync();\n } finally {\n await file.close();\n }\n await rename(temporary, path);\n if (process.platform !== \"win32\") {\n const parent = await open(directory, \"r\");\n try {\n await parent.sync();\n } finally {\n await parent.close();\n }\n }\n } finally {\n await rm(temporary, { force: true });\n }\n },\n async release() {\n if (released) return;\n released = true;\n await release();\n },\n };\n },\n };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-checkpoint.types.js","sourceRoot":"","sources":["../../src/infrastructure/workflow-checkpoint.types.ts"],"names":[],"mappings":"","sourcesContent":["export interface FileWorkflowCheckpointOptions {\n /** Private directory for checkpoint data and local process ownership locks. */\n readonly directory: string;\n}\n"]}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { claude } from "../adapters/agents/claude-adapter.ts";
|
|
2
2
|
export { codex } from "../adapters/agents/codex-adapter.ts";
|
|
3
|
-
export
|
|
3
|
+
export { gemini } from "../adapters/agents/gemini-adapter.ts";
|
|
4
|
+
export type { GeminiSettings } from "../adapters/agents/gemini.types.ts";
|
|
5
|
+
export type { ClaudeSettings, CodexSettings, CodexModelProvider, } from "../adapters/agents/settings.types.ts";
|
package/dist/providers/agents.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/providers/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sCAAsC,CAAC;AAC9D,OAAO,EAAE,KAAK,EAAE,MAAM,qCAAqC,CAAC","sourcesContent":["export { claude } from \"../adapters/agents/claude-adapter.ts\";\nexport { codex } from \"../adapters/agents/codex-adapter.ts\";\nexport type {\n ClaudeSettings,\n CodexSettings,\n} from \"../adapters/agents/settings.types.ts\";\n"]}
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/providers/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sCAAsC,CAAC;AAC9D,OAAO,EAAE,KAAK,EAAE,MAAM,qCAAqC,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,sCAAsC,CAAC","sourcesContent":["export { claude } from \"../adapters/agents/claude-adapter.ts\";\nexport { codex } from \"../adapters/agents/codex-adapter.ts\";\nexport { gemini } from \"../adapters/agents/gemini-adapter.ts\";\nexport type { GeminiSettings } from \"../adapters/agents/gemini.types.ts\";\nexport type {\n ClaudeSettings,\n CodexSettings,\n CodexModelProvider,\n} from \"../adapters/agents/settings.types.ts\";\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { realpath } from "node:fs/promises";
|
|
2
|
+
import { isAbsolute, relative, posix } from "node:path";
|
|
3
|
+
import { invariant } from "../domain/errors.js";
|
|
4
|
+
function contains(parent, child) {
|
|
5
|
+
const offset = relative(parent, child);
|
|
6
|
+
return (!isAbsolute(offset) &&
|
|
7
|
+
offset !== ".." &&
|
|
8
|
+
!offset.startsWith("../") &&
|
|
9
|
+
!offset.startsWith("..\\"));
|
|
10
|
+
}
|
|
11
|
+
export async function validateIsolatedMount(context, source, target) {
|
|
12
|
+
const canonical = await realpath(source);
|
|
13
|
+
for (const path of [
|
|
14
|
+
context.repository,
|
|
15
|
+
context.directory,
|
|
16
|
+
...context.gitDirectories,
|
|
17
|
+
]) {
|
|
18
|
+
const protectedPath = await realpath(path);
|
|
19
|
+
invariant(!contains(canonical, protectedPath) &&
|
|
20
|
+
!contains(protectedPath, canonical), "Isolated repository mounts must not expose the host repository, workspace or Git metadata");
|
|
21
|
+
}
|
|
22
|
+
for (const protectedPath of ["/outpost", "/tmp"]) {
|
|
23
|
+
const offset = posix.relative(protectedPath, target);
|
|
24
|
+
const reverse = posix.relative(target, protectedPath);
|
|
25
|
+
invariant((offset === ".." || offset.startsWith("../")) &&
|
|
26
|
+
(reverse === ".." || reverse.startsWith("../")), "Isolated repository mounts must not overlap workspace or control directories");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=container-isolation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container-isolation.js","sourceRoot":"","sources":["../../src/providers/container-isolation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD,SAAS,QAAQ,CAAC,MAAc,EAAE,KAAa;IAC7C,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACvC,OAAO,CACL,CAAC,UAAU,CAAC,MAAM,CAAC;QACnB,MAAM,KAAK,IAAI;QACf,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC;QACzB,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAC3B,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAuB,EACvB,MAAc,EACd,MAAc;IAEd,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI;QACjB,OAAO,CAAC,UAAU;QAClB,OAAO,CAAC,SAAS;QACjB,GAAG,OAAO,CAAC,cAAc;KAC1B,EAAE,CAAC;QACF,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC3C,SAAS,CACP,CAAC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;YACjC,CAAC,QAAQ,CAAC,aAAa,EAAE,SAAS,CAAC,EACrC,2FAA2F,CAC5F,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,aAAa,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC;QACjD,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;QACtD,SAAS,CACP,CAAC,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YAC3C,CAAC,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EACjD,8EAA8E,CAC/E,CAAC;IACJ,CAAC;AACH,CAAC","sourcesContent":["import { realpath } from \"node:fs/promises\";\nimport { isAbsolute, relative, posix } from \"node:path\";\nimport { invariant } from \"../domain/errors.ts\";\nimport type { SandboxContext } from \"../domain/sandbox.types.ts\";\n\nfunction contains(parent: string, child: string): boolean {\n const offset = relative(parent, child);\n return (\n !isAbsolute(offset) &&\n offset !== \"..\" &&\n !offset.startsWith(\"../\") &&\n !offset.startsWith(\"..\\\\\")\n );\n}\n\nexport async function validateIsolatedMount(\n context: SandboxContext,\n source: string,\n target: string,\n): Promise<void> {\n const canonical = await realpath(source);\n for (const path of [\n context.repository,\n context.directory,\n ...context.gitDirectories,\n ]) {\n const protectedPath = await realpath(path);\n invariant(\n !contains(canonical, protectedPath) &&\n !contains(protectedPath, canonical),\n \"Isolated repository mounts must not expose the host repository, workspace or Git metadata\",\n );\n }\n for (const protectedPath of [\"/outpost\", \"/tmp\"]) {\n const offset = posix.relative(protectedPath, target);\n const reverse = posix.relative(target, protectedPath);\n invariant(\n (offset === \"..\" || offset.startsWith(\"../\")) &&\n (reverse === \"..\" || reverse.startsWith(\"../\")),\n \"Isolated repository mounts must not overlap workspace or control directories\",\n );\n }\n}\n"]}
|