@elie-laloum/outpost 11.1.2 → 11.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.md +2 -1
- package/SECURITY.md +5 -1
- package/dist/adapters/agents/antigravity/antigravity-adapter.js +9 -0
- package/dist/adapters/agents/antigravity/antigravity-adapter.js.map +1 -1
- package/dist/adapters/agents/antigravity/antigravity-hook-plan.d.ts +3 -0
- package/dist/adapters/agents/antigravity/antigravity-hook-plan.js +39 -0
- package/dist/adapters/agents/antigravity/antigravity-hook-plan.js.map +1 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.constants.d.ts +3 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.constants.js +394 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.constants.js.map +1 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.d.ts +2 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.js +6 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.js.map +1 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.types.d.ts +114 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.types.js +2 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.types.js.map +1 -0
- package/dist/adapters/agents/antigravity/antigravity.types.d.ts +1 -0
- package/dist/adapters/agents/antigravity/antigravity.types.js.map +1 -1
- package/dist/adapters/agents/authentication.js +1 -0
- package/dist/adapters/agents/authentication.js.map +1 -1
- package/dist/adapters/agents/claude/claude-adapter.js +15 -0
- package/dist/adapters/agents/claude/claude-adapter.js.map +1 -1
- package/dist/adapters/agents/claude/claude-hook-plan.constants.d.ts +1 -0
- package/dist/adapters/agents/claude/claude-hook-plan.constants.js +20 -0
- package/dist/adapters/agents/claude/claude-hook-plan.constants.js.map +1 -0
- package/dist/adapters/agents/claude/claude-hook-plan.d.ts +4 -0
- package/dist/adapters/agents/claude/claude-hook-plan.js +60 -0
- package/dist/adapters/agents/claude/claude-hook-plan.js.map +1 -0
- package/dist/adapters/agents/claude/claude-hooks.constants.d.ts +3 -0
- package/dist/adapters/agents/claude/claude-hooks.constants.js +2968 -0
- package/dist/adapters/agents/claude/claude-hooks.constants.js.map +1 -0
- package/dist/adapters/agents/claude/claude-hooks.d.ts +2 -0
- package/dist/adapters/agents/claude/claude-hooks.js +6 -0
- package/dist/adapters/agents/claude/claude-hooks.js.map +1 -0
- package/dist/adapters/agents/claude/claude-hooks.types.d.ts +900 -0
- package/dist/adapters/agents/claude/claude-hooks.types.js +2 -0
- package/dist/adapters/agents/claude/claude-hooks.types.js.map +1 -0
- package/dist/adapters/agents/claude/claude-profile.d.ts +1 -0
- package/dist/adapters/agents/claude/claude-profile.js +23 -11
- package/dist/adapters/agents/claude/claude-profile.js.map +1 -1
- package/dist/adapters/agents/codex/codex-adapter.js +17 -1
- package/dist/adapters/agents/codex/codex-adapter.js.map +1 -1
- package/dist/adapters/agents/codex/codex-authentication.js +1 -0
- package/dist/adapters/agents/codex/codex-authentication.js.map +1 -1
- package/dist/adapters/agents/codex/codex-conversations.constants.d.ts +1 -0
- package/dist/adapters/agents/codex/codex-conversations.constants.js +2 -0
- package/dist/adapters/agents/codex/codex-conversations.constants.js.map +1 -0
- package/dist/adapters/agents/codex/codex-conversations.js +8 -5
- package/dist/adapters/agents/codex/codex-conversations.js.map +1 -1
- package/dist/adapters/agents/codex/codex-hook-plan.d.ts +3 -0
- package/dist/adapters/agents/codex/codex-hook-plan.js +72 -0
- package/dist/adapters/agents/codex/codex-hook-plan.js.map +1 -0
- package/dist/adapters/agents/codex/codex-hooks.constants.d.ts +3 -0
- package/dist/adapters/agents/codex/codex-hooks.constants.js +942 -0
- package/dist/adapters/agents/codex/codex-hooks.constants.js.map +1 -0
- package/dist/adapters/agents/codex/codex-hooks.d.ts +2 -0
- package/dist/adapters/agents/codex/codex-hooks.js +6 -0
- package/dist/adapters/agents/codex/codex-hooks.js.map +1 -0
- package/dist/adapters/agents/codex/codex-hooks.types.d.ts +255 -0
- package/dist/adapters/agents/codex/codex-hooks.types.js +2 -0
- package/dist/adapters/agents/codex/codex-hooks.types.js.map +1 -0
- package/dist/adapters/agents/codex/codex-provider.js +2 -2
- package/dist/adapters/agents/codex/codex-provider.js.map +1 -1
- package/dist/adapters/agents/copilot/copilot-adapter.js +14 -0
- package/dist/adapters/agents/copilot/copilot-adapter.js.map +1 -1
- package/dist/adapters/agents/copilot/copilot-hook-plan.d.ts +3 -0
- package/dist/adapters/agents/copilot/copilot-hook-plan.js +26 -0
- package/dist/adapters/agents/copilot/copilot-hook-plan.js.map +1 -0
- package/dist/adapters/agents/copilot/copilot-hooks.constants.d.ts +3 -0
- package/dist/adapters/agents/copilot/copilot-hooks.constants.js +528 -0
- package/dist/adapters/agents/copilot/copilot-hooks.constants.js.map +1 -0
- package/dist/adapters/agents/copilot/copilot-hooks.d.ts +2 -0
- package/dist/adapters/agents/copilot/copilot-hooks.js +6 -0
- package/dist/adapters/agents/copilot/copilot-hooks.js.map +1 -0
- package/dist/adapters/agents/copilot/copilot-hooks.types.d.ts +166 -0
- package/dist/adapters/agents/copilot/copilot-hooks.types.js +2 -0
- package/dist/adapters/agents/copilot/copilot-hooks.types.js.map +1 -0
- package/dist/adapters/agents/copilot/copilot.types.d.ts +1 -0
- package/dist/adapters/agents/copilot/copilot.types.js.map +1 -1
- package/dist/adapters/agents/hook-groups.d.ts +2 -0
- package/dist/adapters/agents/hook-groups.js +17 -0
- package/dist/adapters/agents/hook-groups.js.map +1 -0
- package/dist/adapters/agents/kimi/kimi-adapter.js +16 -1
- package/dist/adapters/agents/kimi/kimi-adapter.js.map +1 -1
- package/dist/adapters/agents/kimi/kimi-hook-plan.d.ts +3 -0
- package/dist/adapters/agents/kimi/kimi-hook-plan.js +33 -0
- package/dist/adapters/agents/kimi/kimi-hook-plan.js.map +1 -0
- package/dist/adapters/agents/kimi/kimi-hooks.constants.d.ts +3 -0
- package/dist/adapters/agents/kimi/kimi-hooks.constants.js +747 -0
- package/dist/adapters/agents/kimi/kimi-hooks.constants.js.map +1 -0
- package/dist/adapters/agents/kimi/kimi-hooks.d.ts +2 -0
- package/dist/adapters/agents/kimi/kimi-hooks.js +6 -0
- package/dist/adapters/agents/kimi/kimi-hooks.js.map +1 -0
- package/dist/adapters/agents/kimi/kimi-hooks.types.d.ts +226 -0
- package/dist/adapters/agents/kimi/kimi-hooks.types.js +2 -0
- package/dist/adapters/agents/kimi/kimi-hooks.types.js.map +1 -0
- package/dist/adapters/agents/kimi/kimi-request.js +2 -0
- package/dist/adapters/agents/kimi/kimi-request.js.map +1 -1
- package/dist/adapters/agents/kimi/kimi.constants.d.ts +1 -0
- package/dist/adapters/agents/kimi/kimi.constants.js +1 -0
- package/dist/adapters/agents/kimi/kimi.constants.js.map +1 -1
- package/dist/adapters/agents/kimi/kimi.types.d.ts +1 -0
- package/dist/adapters/agents/kimi/kimi.types.js.map +1 -1
- package/dist/adapters/agents/native-hooks.d.ts +4 -0
- package/dist/adapters/agents/native-hooks.js +63 -0
- package/dist/adapters/agents/native-hooks.js.map +1 -0
- package/dist/adapters/agents/native-hooks.types.d.ts +22 -0
- package/dist/adapters/agents/native-hooks.types.js +2 -0
- package/dist/adapters/agents/native-hooks.types.js.map +1 -0
- package/dist/adapters/agents/settings.types.d.ts +2 -0
- package/dist/adapters/agents/settings.types.js.map +1 -1
- package/dist/adapters/decisions/system-one-provider.constants.d.ts +1 -1
- package/dist/adapters/decisions/system-one-provider.constants.js +1 -1
- package/dist/adapters/decisions/system-one-provider.constants.js.map +1 -1
- package/dist/adapters/decisions/system-one-provider.js +8 -21
- package/dist/adapters/decisions/system-one-provider.js.map +1 -1
- package/dist/adapters/models/anthropic-model-provider.constants.d.ts +1 -0
- package/dist/adapters/models/anthropic-model-provider.constants.js +4 -0
- package/dist/adapters/models/anthropic-model-provider.constants.js.map +1 -1
- package/dist/adapters/models/anthropic-model-provider.js +7 -1
- package/dist/adapters/models/anthropic-model-provider.js.map +1 -1
- package/dist/adapters/models/http-failure.d.ts +3 -0
- package/dist/adapters/models/http-failure.js +43 -0
- package/dist/adapters/models/http-failure.js.map +1 -0
- package/dist/adapters/models/http-provider.js +14 -20
- package/dist/adapters/models/http-provider.js.map +1 -1
- package/dist/adapters/models/model-protocol.types.d.ts +1 -0
- package/dist/adapters/models/model-protocol.types.js.map +1 -1
- package/dist/adapters/models/model.constants.d.ts +2 -0
- package/dist/adapters/models/model.constants.js +17 -0
- package/dist/adapters/models/model.constants.js.map +1 -1
- package/dist/adapters/models/openai-chat-stream.js +3 -1
- package/dist/adapters/models/openai-chat-stream.js.map +1 -1
- package/dist/adapters/models/openai-responses.js +4 -0
- package/dist/adapters/models/openai-responses.js.map +1 -1
- package/dist/adapters/secrets/aws.js +5 -4
- package/dist/adapters/secrets/aws.js.map +1 -1
- package/dist/adapters/secrets/azure.constants.d.ts +1 -0
- package/dist/adapters/secrets/azure.constants.js +2 -0
- package/dist/adapters/secrets/azure.constants.js.map +1 -0
- package/dist/adapters/secrets/azure.js +2 -1
- package/dist/adapters/secrets/azure.js.map +1 -1
- package/dist/adapters/secrets/gcp.constants.d.ts +1 -0
- package/dist/adapters/secrets/gcp.constants.js +2 -0
- package/dist/adapters/secrets/gcp.constants.js.map +1 -0
- package/dist/adapters/secrets/gcp.js +11 -9
- package/dist/adapters/secrets/gcp.js.map +1 -1
- package/dist/adapters/secrets/infisical.js +3 -2
- package/dist/adapters/secrets/infisical.js.map +1 -1
- package/dist/adapters/secrets/onepassword.constants.d.ts +1 -0
- package/dist/adapters/secrets/onepassword.constants.js +2 -0
- package/dist/adapters/secrets/onepassword.constants.js.map +1 -0
- package/dist/adapters/secrets/onepassword.js +2 -1
- package/dist/adapters/secrets/onepassword.js.map +1 -1
- package/dist/adapters/secrets/secret-source.js +3 -1
- package/dist/adapters/secrets/secret-source.js.map +1 -1
- package/dist/adapters/secrets/vault-response.js +5 -5
- package/dist/adapters/secrets/vault-response.js.map +1 -1
- package/dist/adapters/secrets/vault.js +4 -3
- package/dist/adapters/secrets/vault.js.map +1 -1
- package/dist/adapters/testing/scripted-agent.d.ts +3 -1
- package/dist/adapters/testing/scripted-agent.js +3 -1
- package/dist/adapters/testing/scripted-agent.js.map +1 -1
- package/dist/adapters/tools/edit-tools.js +3 -3
- package/dist/adapters/tools/edit-tools.js.map +1 -1
- package/dist/adapters/tools/git-tools.js +16 -1
- package/dist/adapters/tools/git-tools.js.map +1 -1
- package/dist/adapters/tools/mcp-launcher.constants.d.ts +1 -1
- package/dist/adapters/tools/mcp-launcher.constants.js +29 -7
- package/dist/adapters/tools/mcp-launcher.constants.js.map +1 -1
- package/dist/adapters/tools/mcp-resources.js +5 -1
- package/dist/adapters/tools/mcp-resources.js.map +1 -1
- package/dist/adapters/tools/mcp.constants.d.ts +0 -6
- package/dist/adapters/tools/mcp.constants.js +0 -6
- package/dist/adapters/tools/mcp.constants.js.map +1 -1
- package/dist/adapters/tools/mcp.js +1 -0
- package/dist/adapters/tools/mcp.js.map +1 -1
- package/dist/adapters/tools/sandbox-files.constants.d.ts +1 -0
- package/dist/adapters/tools/sandbox-files.constants.js +17 -0
- package/dist/adapters/tools/sandbox-files.constants.js.map +1 -0
- package/dist/adapters/tools/sandbox-files.d.ts +1 -0
- package/dist/adapters/tools/sandbox-files.js +14 -1
- package/dist/adapters/tools/sandbox-files.js.map +1 -1
- package/dist/adapters/tools/tools.constants.js +1 -0
- package/dist/adapters/tools/tools.constants.js.map +1 -1
- package/dist/adapters/triggers/github-webhook.js +14 -11
- package/dist/adapters/triggers/github-webhook.js.map +1 -1
- package/dist/adapters/triggers/gitlab-webhook.js +16 -13
- package/dist/adapters/triggers/gitlab-webhook.js.map +1 -1
- package/dist/adapters/triggers/slack-request.js +10 -7
- package/dist/adapters/triggers/slack-request.js.map +1 -1
- package/dist/adapters/triggers/standard-webhook.js +10 -7
- package/dist/adapters/triggers/standard-webhook.js.map +1 -1
- package/dist/application/agent-authentication.js +4 -1
- package/dist/application/agent-authentication.js.map +1 -1
- package/dist/application/agent-turn.js +20 -5
- package/dist/application/agent-turn.js.map +1 -1
- package/dist/application/cli-hooks.constants.d.ts +2 -0
- package/dist/application/cli-hooks.constants.js +69 -0
- package/dist/application/cli-hooks.constants.js.map +1 -0
- package/dist/application/cli-hooks.d.ts +3 -0
- package/dist/application/cli-hooks.js +168 -0
- package/dist/application/cli-hooks.js.map +1 -0
- package/dist/application/cli-steering.js +33 -2
- package/dist/application/cli-steering.js.map +1 -1
- package/dist/application/custom-turn.js +10 -1
- package/dist/application/custom-turn.js.map +1 -1
- package/dist/application/diagnostic-probe.d.ts +1 -1
- package/dist/application/diagnostic-probe.js +7 -3
- package/dist/application/diagnostic-probe.js.map +1 -1
- package/dist/application/dispatch-observation.js +4 -0
- package/dist/application/dispatch-observation.js.map +1 -1
- package/dist/application/doctor-agent.d.ts +1 -1
- package/dist/application/doctor-agent.js +2 -2
- package/dist/application/doctor-agent.js.map +1 -1
- package/dist/application/doctor-deadline.d.ts +1 -0
- package/dist/application/doctor-deadline.js +10 -0
- package/dist/application/doctor-deadline.js.map +1 -0
- package/dist/application/doctor-image.js +9 -7
- package/dist/application/doctor-image.js.map +1 -1
- package/dist/application/doctor-sandbox.js +4 -4
- package/dist/application/doctor-sandbox.js.map +1 -1
- package/dist/application/doctor.constants.d.ts +2 -0
- package/dist/application/doctor.constants.js +2 -0
- package/dist/application/doctor.constants.js.map +1 -1
- package/dist/application/doctor.js +12 -8
- package/dist/application/doctor.js.map +1 -1
- package/dist/application/doctor.types.d.ts +2 -0
- package/dist/application/doctor.types.js.map +1 -1
- package/dist/application/file-sandbox.js +49 -11
- package/dist/application/file-sandbox.js.map +1 -1
- package/dist/application/harness-context.js +4 -2
- package/dist/application/harness-context.js.map +1 -1
- package/dist/application/harness-hook-transforms.d.ts +8 -0
- package/dist/application/harness-hook-transforms.js +115 -0
- package/dist/application/harness-hook-transforms.js.map +1 -0
- package/dist/application/harness-hooks.d.ts +5 -3
- package/dist/application/harness-hooks.js +37 -50
- package/dist/application/harness-hooks.js.map +1 -1
- package/dist/application/harness-loop.d.ts +2 -1
- package/dist/application/harness-loop.js +95 -21
- package/dist/application/harness-loop.js.map +1 -1
- package/dist/application/harness-subagent.d.ts +1 -1
- package/dist/application/harness-subagent.js +63 -12
- package/dist/application/harness-subagent.js.map +1 -1
- package/dist/application/harness.types.d.ts +3 -0
- package/dist/application/harness.types.js.map +1 -1
- package/dist/application/hook-invocation.d.ts +4 -0
- package/dist/application/hook-invocation.js +59 -0
- package/dist/application/hook-invocation.js.map +1 -0
- package/dist/application/queue-worker.js +51 -9
- package/dist/application/queue-worker.js.map +1 -1
- package/dist/application/queue-worker.types.d.ts +1 -0
- package/dist/application/queue-worker.types.js.map +1 -1
- package/dist/application/recipes/native-schemas.constants.js +1439 -218
- package/dist/application/recipes/native-schemas.constants.js.map +1 -1
- package/dist/application/recovery-inspection.js +4 -1
- package/dist/application/recovery-inspection.js.map +1 -1
- package/dist/application/remote-download.js +15 -5
- package/dist/application/remote-download.js.map +1 -1
- package/dist/application/remote-paths.d.ts +1 -0
- package/dist/application/remote-paths.js +7 -0
- package/dist/application/remote-paths.js.map +1 -0
- package/dist/application/remote-validation.js +40 -9
- package/dist/application/remote-validation.js.map +1 -1
- package/dist/application/remote-workspace.js +17 -2
- package/dist/application/remote-workspace.js.map +1 -1
- package/dist/application/repetition-watchdog.js +3 -1
- package/dist/application/repetition-watchdog.js.map +1 -1
- package/dist/application/sandbox-attach.js +38 -9
- package/dist/application/sandbox-attach.js.map +1 -1
- package/dist/application/sandbox-dispatch.js +7 -1
- package/dist/application/sandbox-dispatch.js.map +1 -1
- package/dist/application/schedules.js +2 -0
- package/dist/application/schedules.js.map +1 -1
- package/dist/application/secrets.js +4 -0
- package/dist/application/secrets.js.map +1 -1
- package/dist/application/tool-execution.js +28 -8
- package/dist/application/tool-execution.js.map +1 -1
- package/dist/application/transport-retention.js +3 -3
- package/dist/application/transport-retention.js.map +1 -1
- package/dist/application/workspace-fingerprint.d.ts +1 -0
- package/dist/application/workspace-fingerprint.js +19 -4
- package/dist/application/workspace-fingerprint.js.map +1 -1
- package/dist/cli/doctor-command.js +12 -2
- package/dist/cli/doctor-command.js.map +1 -1
- package/dist/cli/image.js +2 -0
- package/dist/cli/image.js.map +1 -1
- package/dist/cli/main.constants.d.ts +14 -2
- package/dist/cli/main.constants.js +27 -1
- package/dist/cli/main.constants.js.map +1 -1
- package/dist/cli/project-settings.js +7 -1
- package/dist/cli/project-settings.js.map +1 -1
- package/dist/cli/recipe-yaml.js +8 -0
- package/dist/cli/recipe-yaml.js.map +1 -1
- package/dist/cli/recovery-command.js +3 -0
- package/dist/cli/recovery-command.js.map +1 -1
- package/dist/cli/recovery-unlock-command.d.ts +2 -0
- package/dist/cli/recovery-unlock-command.js +19 -0
- package/dist/cli/recovery-unlock-command.js.map +1 -0
- package/dist/cli/scaffold-files.js +4 -1
- package/dist/cli/scaffold-files.js.map +1 -1
- package/dist/cli/scaffold-validation.js +3 -0
- package/dist/cli/scaffold-validation.js.map +1 -1
- package/dist/cli/scaffold.js +2 -0
- package/dist/cli/scaffold.js.map +1 -1
- package/dist/domain/agent-hook.types.d.ts +28 -0
- package/dist/domain/agent-hook.types.js +2 -0
- package/dist/domain/agent-hook.types.js.map +1 -0
- package/dist/domain/agent-profile-hooks.d.ts +2 -0
- package/dist/domain/agent-profile-hooks.js +52 -0
- package/dist/domain/agent-profile-hooks.js.map +1 -0
- package/dist/domain/agent-profile-permissions.js +11 -1
- package/dist/domain/agent-profile-permissions.js.map +1 -1
- package/dist/domain/agent-profile.constants.d.ts +1 -0
- package/dist/domain/agent-profile.constants.js +9 -0
- package/dist/domain/agent-profile.constants.js.map +1 -1
- package/dist/domain/agent-profile.js +6 -1
- package/dist/domain/agent-profile.js.map +1 -1
- package/dist/domain/agent-profile.types.d.ts +11 -0
- package/dist/domain/agent-profile.types.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/container-image.d.ts +1 -0
- package/dist/domain/container-image.js +8 -0
- package/dist/domain/container-image.js.map +1 -0
- package/dist/domain/context.constants.d.ts +1 -0
- package/dist/domain/context.constants.js +1 -0
- package/dist/domain/context.constants.js.map +1 -1
- package/dist/domain/context.js +6 -1
- package/dist/domain/context.js.map +1 -1
- package/dist/domain/egress.js +6 -1
- package/dist/domain/egress.js.map +1 -1
- package/dist/domain/glob.js +1 -1
- package/dist/domain/glob.js.map +1 -1
- package/dist/domain/harness.js +4 -1
- package/dist/domain/harness.js.map +1 -1
- package/dist/domain/hook-command.d.ts +2 -0
- package/dist/domain/hook-command.js +26 -0
- package/dist/domain/hook-command.js.map +1 -0
- package/dist/domain/hook-command.types.d.ts +7 -0
- package/dist/domain/hook-command.types.js +2 -0
- package/dist/domain/hook-command.types.js.map +1 -0
- package/dist/domain/hook-decision.d.ts +2 -0
- package/dist/domain/hook-decision.js +38 -0
- package/dist/domain/hook-decision.js.map +1 -0
- package/dist/domain/hook.constants.d.ts +3 -0
- package/dist/domain/hook.constants.js +31 -1
- package/dist/domain/hook.constants.js.map +1 -1
- package/dist/domain/hook.js +49 -5
- package/dist/domain/hook.js.map +1 -1
- package/dist/domain/hook.types.d.ts +82 -5
- package/dist/domain/hook.types.js.map +1 -1
- package/dist/domain/mcp-server.constants.d.ts +6 -0
- package/dist/domain/mcp-server.constants.js +6 -0
- package/dist/domain/mcp-server.constants.js.map +1 -1
- package/dist/domain/mcp-server.js +1 -0
- package/dist/domain/mcp-server.js.map +1 -1
- package/dist/domain/permissions.types.d.ts +1 -0
- package/dist/domain/permissions.types.js.map +1 -1
- package/dist/domain/pricing.js +4 -2
- package/dist/domain/pricing.js.map +1 -1
- package/dist/domain/redaction.js +6 -3
- package/dist/domain/redaction.js.map +1 -1
- package/dist/domain/secret-fault.d.ts +4 -0
- package/dist/domain/secret-fault.js +11 -0
- package/dist/domain/secret-fault.js.map +1 -0
- package/dist/domain/secrets.js +3 -2
- package/dist/domain/secrets.js.map +1 -1
- package/dist/domain/steering.js +2 -0
- package/dist/domain/steering.js.map +1 -1
- package/dist/domain/steering.types.d.ts +1 -1
- package/dist/domain/steering.types.js.map +1 -1
- package/dist/domain/transport.js +5 -1
- package/dist/domain/transport.js.map +1 -1
- package/dist/domain/trigger-payload.d.ts +4 -0
- package/dist/domain/trigger-payload.js +15 -0
- package/dist/domain/trigger-payload.js.map +1 -0
- package/dist/domain/workflow/checkpoint.js +19 -2
- package/dist/domain/workflow/checkpoint.js.map +1 -1
- package/dist/domain/workflow/retry.constants.d.ts +1 -0
- package/dist/domain/workflow/retry.constants.js +1 -0
- package/dist/domain/workflow/retry.constants.js.map +1 -1
- package/dist/domain/workflow/retry.js +6 -2
- package/dist/domain/workflow/retry.js.map +1 -1
- package/dist/domain/workflow/task-runner.js +5 -3
- package/dist/domain/workflow/task-runner.js.map +1 -1
- package/dist/domain/workflow/workflow-state.js +2 -1
- package/dist/domain/workflow/workflow-state.js.map +1 -1
- package/dist/domain/workflow.types.d.ts +1 -0
- package/dist/domain/workflow.types.js.map +1 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/conversations/transcript-store.js +32 -5
- package/dist/infrastructure/conversations/transcript-store.js.map +1 -1
- package/dist/infrastructure/files.d.ts +1 -0
- package/dist/infrastructure/files.js +8 -4
- package/dist/infrastructure/files.js.map +1 -1
- package/dist/infrastructure/git/integration-candidate.js +3 -2
- package/dist/infrastructure/git/integration-candidate.js.map +1 -1
- package/dist/infrastructure/git/lock-recovery.d.ts +3 -0
- package/dist/infrastructure/git/lock-recovery.js +58 -0
- package/dist/infrastructure/git/lock-recovery.js.map +1 -0
- package/dist/infrastructure/git/lock-recovery.types.d.ts +11 -0
- package/dist/infrastructure/git/lock-recovery.types.js +2 -0
- package/dist/infrastructure/git/lock-recovery.types.js.map +1 -0
- package/dist/infrastructure/git/managed-worktree.js +5 -8
- package/dist/infrastructure/git/managed-worktree.js.map +1 -1
- package/dist/infrastructure/git/verification-command.js +35 -30
- package/dist/infrastructure/git/verification-command.js.map +1 -1
- package/dist/infrastructure/git/workspace-lease.js +12 -5
- package/dist/infrastructure/git/workspace-lease.js.map +1 -1
- package/dist/infrastructure/hook-configuration.constants.d.ts +1 -0
- package/dist/infrastructure/hook-configuration.constants.js +59 -0
- package/dist/infrastructure/hook-configuration.constants.js.map +1 -0
- package/dist/infrastructure/hook-configuration.d.ts +3 -0
- package/dist/infrastructure/hook-configuration.js +16 -0
- package/dist/infrastructure/hook-configuration.js.map +1 -0
- package/dist/infrastructure/hook-configuration.types.d.ts +14 -0
- package/dist/infrastructure/hook-configuration.types.js +2 -0
- package/dist/infrastructure/hook-configuration.types.js.map +1 -0
- package/dist/infrastructure/http-transport.constants.d.ts +1 -0
- package/dist/infrastructure/http-transport.constants.js +14 -0
- package/dist/infrastructure/http-transport.constants.js.map +1 -0
- package/dist/infrastructure/http-transport.d.ts +7 -0
- package/dist/infrastructure/http-transport.js +19 -0
- package/dist/infrastructure/http-transport.js.map +1 -0
- package/dist/infrastructure/input-failure.d.ts +4 -0
- package/dist/infrastructure/input-failure.js +14 -0
- package/dist/infrastructure/input-failure.js.map +1 -0
- package/dist/infrastructure/inspection-file.d.ts +1 -0
- package/dist/infrastructure/inspection-file.js +8 -2
- package/dist/infrastructure/inspection-file.js.map +1 -1
- package/dist/infrastructure/local-transport.js +16 -11
- package/dist/infrastructure/local-transport.js.map +1 -1
- package/dist/infrastructure/process.constants.d.ts +1 -0
- package/dist/infrastructure/process.constants.js +1 -0
- package/dist/infrastructure/process.constants.js.map +1 -1
- package/dist/infrastructure/process.d.ts +1 -0
- package/dist/infrastructure/process.js +48 -8
- package/dist/infrastructure/process.js.map +1 -1
- package/dist/infrastructure/reservation-ledger.d.ts +2 -0
- package/dist/infrastructure/reservation-ledger.js +84 -0
- package/dist/infrastructure/reservation-ledger.js.map +1 -0
- package/dist/infrastructure/reservation-recovery.d.ts +4 -0
- package/dist/infrastructure/reservation-recovery.js +28 -0
- package/dist/infrastructure/reservation-recovery.js.map +1 -0
- package/dist/infrastructure/s3-tombstones.d.ts +3 -0
- package/dist/infrastructure/s3-tombstones.js +46 -0
- package/dist/infrastructure/s3-tombstones.js.map +1 -0
- package/dist/infrastructure/s3-tombstones.types.d.ts +6 -0
- package/dist/infrastructure/s3-tombstones.types.js +2 -0
- package/dist/infrastructure/s3-tombstones.types.js.map +1 -0
- package/dist/infrastructure/s3-transport.d.ts +2 -0
- package/dist/infrastructure/s3-transport.js +4 -2
- package/dist/infrastructure/s3-transport.js.map +1 -1
- package/dist/infrastructure/sse.js +6 -3
- package/dist/infrastructure/sse.js.map +1 -1
- package/dist/infrastructure/task-queue-bullmq-connection.d.ts +3 -0
- package/dist/infrastructure/task-queue-bullmq-connection.js +32 -0
- package/dist/infrastructure/task-queue-bullmq-connection.js.map +1 -0
- package/dist/infrastructure/task-queue-bullmq-connection.types.d.ts +8 -0
- package/dist/infrastructure/task-queue-bullmq-connection.types.js +2 -0
- package/dist/infrastructure/task-queue-bullmq-connection.types.js.map +1 -0
- package/dist/infrastructure/task-queue-bullmq-resources.js +21 -15
- package/dist/infrastructure/task-queue-bullmq-resources.js.map +1 -1
- package/dist/infrastructure/task-queue-bullmq-state.d.ts +1 -0
- package/dist/infrastructure/task-queue-bullmq-state.js +1 -0
- package/dist/infrastructure/task-queue-bullmq-state.js.map +1 -1
- package/dist/infrastructure/task-queue-bullmq.constants.d.ts +2 -1
- package/dist/infrastructure/task-queue-bullmq.constants.js +2 -1
- package/dist/infrastructure/task-queue-bullmq.constants.js.map +1 -1
- package/dist/infrastructure/task-queue-bullmq.js +10 -1
- package/dist/infrastructure/task-queue-bullmq.js.map +1 -1
- package/dist/infrastructure/task-queue.js +13 -4
- package/dist/infrastructure/task-queue.js.map +1 -1
- package/dist/infrastructure/transfer-copy.d.ts +1 -0
- package/dist/infrastructure/transfer-copy.js +16 -1
- package/dist/infrastructure/transfer-copy.js.map +1 -1
- package/dist/infrastructure/transport-archive.d.ts +3 -3
- package/dist/infrastructure/transport-archive.js +71 -48
- package/dist/infrastructure/transport-archive.js.map +1 -1
- package/dist/infrastructure/transport-archive.types.d.ts +3 -0
- package/dist/infrastructure/transport-archive.types.js.map +1 -1
- package/dist/infrastructure/transport-checkpoint.js +14 -4
- package/dist/infrastructure/transport-checkpoint.js.map +1 -1
- package/dist/infrastructure/transport-envelope.d.ts +1 -0
- package/dist/infrastructure/transport-envelope.js +22 -5
- package/dist/infrastructure/transport-envelope.js.map +1 -1
- package/dist/infrastructure/transport-reservations.constants.d.ts +2 -0
- package/dist/infrastructure/transport-reservations.constants.js +3 -0
- package/dist/infrastructure/transport-reservations.constants.js.map +1 -0
- package/dist/infrastructure/transport-reservations.d.ts +1 -2
- package/dist/infrastructure/transport-reservations.js +18 -22
- package/dist/infrastructure/transport-reservations.js.map +1 -1
- package/dist/infrastructure/transport-reservations.types.d.ts +23 -2
- package/dist/infrastructure/transport-reservations.types.js.map +1 -1
- package/dist/infrastructure/trigger-server.js +12 -9
- package/dist/infrastructure/trigger-server.js.map +1 -1
- package/dist/infrastructure/trigger-server.types.d.ts +1 -1
- package/dist/infrastructure/trigger-server.types.js.map +1 -1
- package/dist/infrastructure/workflow-checkpoint.constants.d.ts +1 -0
- package/dist/infrastructure/workflow-checkpoint.constants.js +1 -0
- package/dist/infrastructure/workflow-checkpoint.constants.js.map +1 -1
- package/dist/infrastructure/workspace-lock.constants.d.ts +2 -1
- package/dist/infrastructure/workspace-lock.constants.js +2 -1
- package/dist/infrastructure/workspace-lock.constants.js.map +1 -1
- package/dist/infrastructure/workspace-lock.js +48 -10
- package/dist/infrastructure/workspace-lock.js.map +1 -1
- package/dist/providers/cloud-cache.js +14 -9
- package/dist/providers/cloud-cache.js.map +1 -1
- package/dist/providers/cloud-cache.types.d.ts +1 -0
- package/dist/providers/cloud-cache.types.js.map +1 -1
- package/dist/providers/cloud-files.js +3 -4
- package/dist/providers/cloud-files.js.map +1 -1
- package/dist/providers/cloud-input.constants.d.ts +2 -2
- package/dist/providers/cloud-input.constants.js +2 -1
- package/dist/providers/cloud-input.constants.js.map +1 -1
- package/dist/providers/cloud-input.d.ts +2 -2
- package/dist/providers/cloud-input.js +14 -3
- package/dist/providers/cloud-input.js.map +1 -1
- package/dist/providers/container-command.js +30 -5
- package/dist/providers/container-command.js.map +1 -1
- package/dist/providers/container-egress.constants.d.ts +7 -0
- package/dist/providers/container-egress.constants.js +8 -0
- package/dist/providers/container-egress.constants.js.map +1 -0
- package/dist/providers/container-egress.d.ts +7 -0
- package/dist/providers/container-egress.js +101 -0
- package/dist/providers/container-egress.js.map +1 -0
- package/dist/providers/container-files.js +10 -11
- package/dist/providers/container-files.js.map +1 -1
- package/dist/providers/container-mounts.js +3 -0
- package/dist/providers/container-mounts.js.map +1 -1
- package/dist/providers/container-network.js +16 -1
- package/dist/providers/container-network.js.map +1 -1
- package/dist/providers/container-plan.js +7 -10
- package/dist/providers/container-plan.js.map +1 -1
- package/dist/providers/container-recovery.js +8 -3
- package/dist/providers/container-recovery.js.map +1 -1
- package/dist/providers/container.js +36 -5
- package/dist/providers/container.js.map +1 -1
- package/dist/providers/container.types.d.ts +1 -0
- package/dist/providers/container.types.js.map +1 -1
- package/dist/providers/daytona-command.constants.js +4 -1
- package/dist/providers/daytona-command.constants.js.map +1 -1
- package/dist/providers/daytona-command.js +39 -16
- package/dist/providers/daytona-command.js.map +1 -1
- package/dist/providers/daytona-files.js +5 -5
- package/dist/providers/daytona-files.js.map +1 -1
- package/dist/providers/daytona-output.js +11 -3
- package/dist/providers/daytona-output.js.map +1 -1
- package/dist/providers/daytona.js +11 -9
- package/dist/providers/daytona.js.map +1 -1
- package/dist/providers/egress/address.d.ts +3 -0
- package/dist/providers/egress/address.js +26 -0
- package/dist/providers/egress/address.js.map +1 -0
- package/dist/providers/egress/egress.constants.d.ts +22 -0
- package/dist/providers/egress/egress.constants.js +23 -0
- package/dist/providers/egress/egress.constants.js.map +1 -0
- package/dist/providers/egress/egress.types.d.ts +11 -0
- package/dist/providers/egress/egress.types.js +2 -0
- package/dist/providers/egress/egress.types.js.map +1 -0
- package/dist/providers/egress/firewall.d.ts +3 -0
- package/dist/providers/egress/firewall.js +29 -0
- package/dist/providers/egress/firewall.js.map +1 -0
- package/dist/providers/egress/main.d.ts +1 -0
- package/dist/providers/egress/main.js +90 -0
- package/dist/providers/egress/main.js.map +1 -0
- package/dist/providers/egress/policy.d.ts +5 -0
- package/dist/providers/egress/policy.js +54 -0
- package/dist/providers/egress/policy.js.map +1 -0
- package/dist/providers/egress/proxy.d.ts +2 -0
- package/dist/providers/egress/proxy.js +129 -0
- package/dist/providers/egress/proxy.js.map +1 -0
- package/dist/providers/egress/tls-hello.d.ts +1 -0
- package/dist/providers/egress/tls-hello.js +75 -0
- package/dist/providers/egress/tls-hello.js.map +1 -0
- package/dist/providers/firecracker-command.js +12 -6
- package/dist/providers/firecracker-command.js.map +1 -1
- package/dist/providers/local-files.d.ts +2 -0
- package/dist/providers/local-files.js +24 -0
- package/dist/providers/local-files.js.map +1 -0
- package/dist/providers/local.js +2 -20
- package/dist/providers/local.js.map +1 -1
- package/dist/providers/vercel-command.js +33 -9
- package/dist/providers/vercel-command.js.map +1 -1
- package/dist/providers/vercel.js +11 -9
- package/dist/providers/vercel.js.map +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/package.json +2 -2
- package/recipe-configuration.schema.json +2164 -35
- package/recipe.schema.json +2512 -404
|
@@ -4,4 +4,5 @@ export declare function encodeObject(key: string, bytes: Uint8Array): {
|
|
|
4
4
|
data: Buffer<ArrayBuffer>;
|
|
5
5
|
};
|
|
6
6
|
export declare function decodeObject(data: Uint8Array, key: string, maxBytes: number): TransportObject;
|
|
7
|
+
export declare function decodeObjectEntry(data: Uint8Array, key: string, fileSize: number, maxBytes: number): TransportEntry;
|
|
7
8
|
export declare function readLimit(maxBytes?: number): number;
|
|
@@ -15,8 +15,27 @@ export function encodeObject(key, bytes) {
|
|
|
15
15
|
}
|
|
16
16
|
export function decodeObject(data, key, maxBytes) {
|
|
17
17
|
const buffer = Buffer.from(data);
|
|
18
|
-
const value = JSON.parse(buffer.subarray(0, transportDefaults.headerBytes).toString());
|
|
19
18
|
const bytes = buffer.subarray(transportDefaults.headerBytes);
|
|
19
|
+
return {
|
|
20
|
+
...decodeObjectEntry(buffer, key, data.byteLength, maxBytes),
|
|
21
|
+
bytes,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function decodeObjectEntry(data, key, fileSize, maxBytes) {
|
|
25
|
+
const size = fileSize - transportDefaults.headerBytes;
|
|
26
|
+
if (!Number.isSafeInteger(size) ||
|
|
27
|
+
size < 0 ||
|
|
28
|
+
size > maxBytes ||
|
|
29
|
+
data.byteLength < transportDefaults.headerBytes)
|
|
30
|
+
throw new Error("Invalid or oversized transport object");
|
|
31
|
+
const value = JSON.parse(Buffer.from(data.subarray(0, transportDefaults.headerBytes)).toString());
|
|
32
|
+
if (value &&
|
|
33
|
+
typeof value === "object" &&
|
|
34
|
+
"key" in value &&
|
|
35
|
+
typeof value.key === "string" &&
|
|
36
|
+
value.key !== key &&
|
|
37
|
+
value.key.toLowerCase() === key.toLowerCase())
|
|
38
|
+
throw new Error("Transport key casing conflicts with the stored key");
|
|
20
39
|
if (!value ||
|
|
21
40
|
typeof value !== "object" ||
|
|
22
41
|
!("key" in value) ||
|
|
@@ -25,8 +44,7 @@ export function decodeObject(data, key, maxBytes) {
|
|
|
25
44
|
typeof value.revision !== "string" ||
|
|
26
45
|
!value.revision ||
|
|
27
46
|
!("size" in value) ||
|
|
28
|
-
value.size !==
|
|
29
|
-
bytes.length > maxBytes ||
|
|
47
|
+
value.size !== size ||
|
|
30
48
|
!("modifiedAt" in value) ||
|
|
31
49
|
typeof value.modifiedAt !== "string" ||
|
|
32
50
|
!Number.isFinite(Date.parse(value.modifiedAt)))
|
|
@@ -34,9 +52,8 @@ export function decodeObject(data, key, maxBytes) {
|
|
|
34
52
|
return {
|
|
35
53
|
key,
|
|
36
54
|
revision: value.revision,
|
|
37
|
-
size
|
|
55
|
+
size,
|
|
38
56
|
modifiedAt: value.modifiedAt,
|
|
39
|
-
bytes,
|
|
40
57
|
};
|
|
41
58
|
}
|
|
42
59
|
export function readLimit(maxBytes = transportDefaults.maxBytes) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport-envelope.js","sourceRoot":"","sources":["../../src/infrastructure/transport-envelope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAKzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,KAAiB;IACzD,IAAI,KAAK,CAAC,UAAU,GAAG,iBAAiB,CAAC,QAAQ;QAC/C,MAAM,IAAI,KAAK,CACb,mEAAmE,CACpE,CAAC;IACJ,MAAM,KAAK,GAAmB;QAC5B,GAAG;QACH,QAAQ,EAAE,UAAU,EAAE;QACtB,IAAI,EAAE,KAAK,CAAC,UAAU;QACtB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC,CAAC;IACF,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;IAChE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IACpC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,IAAgB,EAChB,GAAW,EACX,QAAgB;IAEhB,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,KAAK,GAAY,IAAI,CAAC,KAAK,CAC/B,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"transport-envelope.js","sourceRoot":"","sources":["../../src/infrastructure/transport-envelope.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type {\n TransportEntry,\n TransportObject,\n} from \"../domain/transport.types.ts\";\nimport { transportDefaults } from \"./transport.constants.ts\";\n\nexport function encodeObject(key: string, bytes: Uint8Array) {\n if (bytes.byteLength > transportDefaults.maxBytes)\n throw new Error(\n \"Transport object exceeds 64 MiB; split large payloads into chunks\",\n );\n const entry: TransportEntry = {\n key,\n revision: randomUUID(),\n size: bytes.byteLength,\n modifiedAt: new Date().toISOString(),\n };\n const header = Buffer.alloc(transportDefaults.headerBytes, \" \");\n header.write(JSON.stringify(entry));\n return { entry, data: Buffer.concat([header, bytes]) };\n}\n\nexport function decodeObject(\n data: Uint8Array,\n key: string,\n maxBytes: number,\n): TransportObject {\n const buffer = Buffer.from(data);\n const bytes = buffer.subarray(transportDefaults.headerBytes);\n return {\n ...decodeObjectEntry(buffer, key, data.byteLength, maxBytes),\n bytes,\n };\n}\n\nexport function decodeObjectEntry(\n data: Uint8Array,\n key: string,\n fileSize: number,\n maxBytes: number,\n): TransportEntry {\n const size = fileSize - transportDefaults.headerBytes;\n if (\n !Number.isSafeInteger(size) ||\n size < 0 ||\n size > maxBytes ||\n data.byteLength < transportDefaults.headerBytes\n )\n throw new Error(\"Invalid or oversized transport object\");\n const value: unknown = JSON.parse(\n Buffer.from(data.subarray(0, transportDefaults.headerBytes)).toString(),\n );\n if (\n value &&\n typeof value === \"object\" &&\n \"key\" in value &&\n typeof value.key === \"string\" &&\n value.key !== key &&\n value.key.toLowerCase() === key.toLowerCase()\n )\n throw new Error(\"Transport key casing conflicts with the stored key\");\n if (\n !value ||\n typeof value !== \"object\" ||\n !(\"key\" in value) ||\n value.key !== key ||\n !(\"revision\" in value) ||\n typeof value.revision !== \"string\" ||\n !value.revision ||\n !(\"size\" in value) ||\n value.size !== size ||\n !(\"modifiedAt\" in value) ||\n typeof value.modifiedAt !== \"string\" ||\n !Number.isFinite(Date.parse(value.modifiedAt))\n )\n throw new Error(\"Invalid or oversized transport object\");\n return {\n key,\n revision: value.revision,\n size,\n modifiedAt: value.modifiedAt,\n };\n}\n\nexport function readLimit(maxBytes = transportDefaults.maxBytes): number {\n if (!Number.isSafeInteger(maxBytes) || maxBytes < 0)\n throw new Error(\"Invalid transport byte limit\");\n return maxBytes;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-reservations.constants.js","sourceRoot":"","sources":["../../src/infrastructure/transport-reservations.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG,qBAAqB,CAAC;AAC1D,MAAM,CAAC,MAAM,oBAAoB,GAC/B,gEAAgE,CAAC","sourcesContent":["export const reservationLedgerKey = \"reservations/ledger\";\nexport const reservationIdPattern =\n /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/;\n"]}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Transport } from "../domain/transport.types.ts";
|
|
2
2
|
import type { StorageReservation, StorageReservationOptions } from "./storage-reservations.types.ts";
|
|
3
|
-
|
|
4
|
-
export declare function reservationLedger(value: unknown): ReservationLedger;
|
|
3
|
+
export { reservationLedger } from "./reservation-ledger.ts";
|
|
5
4
|
export declare function reserveTransportStorage(transporter: Transport, repository: string, options: StorageReservationOptions, measureUsage?: () => Promise<number>): Promise<StorageReservation>;
|
|
@@ -3,25 +3,12 @@ import { randomUUID } from "node:crypto";
|
|
|
3
3
|
import { TransportConflict } from "../domain/transport.js";
|
|
4
4
|
import { invariant, recordRecovery } from "../domain/errors.js";
|
|
5
5
|
import { jsonBytes, jsonObject } from "./transport-json.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"format" in value &&
|
|
13
|
-
value.format === 1 &&
|
|
14
|
-
"reservations" in value &&
|
|
15
|
-
value.reservations &&
|
|
16
|
-
typeof value.reservations === "object" &&
|
|
17
|
-
!Array.isArray(value.reservations), "Invalid reservation ledger");
|
|
18
|
-
const entries = Object.entries(value.reservations);
|
|
19
|
-
invariant(entries.every(([id, bytes]) => /^[a-f0-9-]{36}$/.test(id) &&
|
|
20
|
-
typeof bytes === "number" &&
|
|
21
|
-
Number.isSafeInteger(bytes) &&
|
|
22
|
-
bytes >= 0), "Invalid reservation entry");
|
|
23
|
-
return { format: 1, reservations: Object.fromEntries(entries) };
|
|
24
|
-
}
|
|
6
|
+
import { reservationLedger } from "./reservation-ledger.js";
|
|
7
|
+
import { reservationLedgerKey as key } from "./transport-reservations.constants.js";
|
|
8
|
+
import { localProcessIdentity } from "./git/process-identity.js";
|
|
9
|
+
import { hostname } from "node:os";
|
|
10
|
+
export { reservationLedger } from "./reservation-ledger.js";
|
|
11
|
+
const ownerId = randomUUID();
|
|
25
12
|
async function payloadUsage(transporter, maxEntries, signal) {
|
|
26
13
|
let usage = 0, count = 0;
|
|
27
14
|
for await (const entry of transporter.list("", signal ? { signal } : {})) {
|
|
@@ -37,6 +24,15 @@ export async function reserveTransportStorage(transporter, repository, options,
|
|
|
37
24
|
Number.isSafeInteger(options.reserveBytes) &&
|
|
38
25
|
options.reserveBytes >= 0, "Invalid reservation byte limit");
|
|
39
26
|
const id = randomUUID();
|
|
27
|
+
const identity = await localProcessIdentity();
|
|
28
|
+
const owner = {
|
|
29
|
+
id: ownerId,
|
|
30
|
+
host: hostname(),
|
|
31
|
+
pid: process.pid,
|
|
32
|
+
createdAt: new Date().toISOString(),
|
|
33
|
+
repository,
|
|
34
|
+
...(identity ? { identity } : {}),
|
|
35
|
+
};
|
|
40
36
|
const maxEntries = options.maxEntries ?? transportDefaults.maxEntries;
|
|
41
37
|
invariant(Number.isSafeInteger(maxEntries) && maxEntries > 0, "Invalid reservation entry limit");
|
|
42
38
|
async function update(release) {
|
|
@@ -52,12 +48,12 @@ export async function reserveTransportStorage(transporter, repository, options,
|
|
|
52
48
|
const usage = measureUsage
|
|
53
49
|
? await measureUsage()
|
|
54
50
|
: await payloadUsage(transporter, maxEntries, options.signal);
|
|
55
|
-
const reserved = Object.values(reservations).reduce((sum, value) => sum + value, 0);
|
|
51
|
+
const reserved = Object.values(reservations).reduce((sum, value) => sum + value.bytes, 0);
|
|
56
52
|
invariant(usage + reserved + options.reserveBytes <= options.maxBytes, "Outpost storage reservation admission refused");
|
|
57
|
-
reservations[id] = options.reserveBytes;
|
|
53
|
+
reservations[id] = { bytes: options.reserveBytes, owner };
|
|
58
54
|
}
|
|
59
55
|
try {
|
|
60
|
-
await transporter.write(key, jsonBytes({ format:
|
|
56
|
+
await transporter.write(key, jsonBytes({ format: 2, reservations }), {
|
|
61
57
|
ifRevision: current?.revision ?? null,
|
|
62
58
|
...(!release && options.signal ? { signal: options.signal } : {}),
|
|
63
59
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport-reservations.js","sourceRoot":"","sources":["../../src/infrastructure/transport-reservations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"transport-reservations.js","sourceRoot":"","sources":["../../src/infrastructure/transport-reservations.ts"],"names":[],"mappings":"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","sourcesContent":["import { transportDefaults } from \"./transport.constants.ts\";\nimport { randomUUID } from \"node:crypto\";\nimport type { Transport } from \"../domain/transport.types.ts\";\nimport { TransportConflict } from \"../domain/transport.ts\";\nimport { invariant, recordRecovery } from \"../domain/errors.ts\";\nimport { jsonBytes, jsonObject } from \"./transport-json.ts\";\nimport type {\n StorageReservation,\n StorageReservationOptions,\n} from \"./storage-reservations.types.ts\";\nimport { reservationLedger } from \"./reservation-ledger.ts\";\nimport { reservationLedgerKey as key } from \"./transport-reservations.constants.ts\";\nimport { localProcessIdentity } from \"./git/process-identity.ts\";\nimport { hostname } from \"node:os\";\nexport { reservationLedger } from \"./reservation-ledger.ts\";\n\nconst ownerId = randomUUID();\n\nasync function payloadUsage(\n transporter: Transport,\n maxEntries: number,\n signal?: AbortSignal,\n): Promise<number> {\n let usage = 0,\n count = 0;\n for await (const entry of transporter.list(\"\", signal ? { signal } : {})) {\n invariant(++count <= maxEntries, \"Reservation inventory is incomplete\");\n if (entry.key !== key) usage += entry.size;\n }\n return usage;\n}\n\nexport async function reserveTransportStorage(\n transporter: Transport,\n repository: string,\n options: StorageReservationOptions,\n measureUsage?: () => Promise<number>,\n): Promise<StorageReservation> {\n invariant(\n Number.isSafeInteger(options.maxBytes) &&\n options.maxBytes >= 0 &&\n Number.isSafeInteger(options.reserveBytes) &&\n options.reserveBytes >= 0,\n \"Invalid reservation byte limit\",\n );\n const id = randomUUID();\n const identity = await localProcessIdentity();\n const owner = {\n id: ownerId,\n host: hostname(),\n pid: process.pid,\n createdAt: new Date().toISOString(),\n repository,\n ...(identity ? { identity } : {}),\n };\n const maxEntries = options.maxEntries ?? transportDefaults.maxEntries;\n invariant(\n Number.isSafeInteger(maxEntries) && maxEntries > 0,\n \"Invalid reservation entry limit\",\n );\n async function update(release: boolean): Promise<void> {\n for (\n let attempt = 0;\n attempt < transportDefaults.mutationAttempts;\n attempt++\n ) {\n if (!release) options.signal?.throwIfAborted();\n const current = await transporter.read(key);\n const ledger = reservationLedger(jsonObject(current));\n const reservations = { ...ledger.reservations };\n if (release) delete reservations[id];\n if (!release) {\n const usage = measureUsage\n ? await measureUsage()\n : await payloadUsage(transporter, maxEntries, options.signal);\n const reserved = Object.values(reservations).reduce(\n (sum, value) => sum + value.bytes,\n 0,\n );\n invariant(\n usage + reserved + options.reserveBytes <= options.maxBytes,\n \"Outpost storage reservation admission refused\",\n );\n reservations[id] = { bytes: options.reserveBytes, owner };\n }\n try {\n await transporter.write(key, jsonBytes({ format: 2, reservations }), {\n ifRevision: current?.revision ?? null,\n ...(!release && options.signal ? { signal: options.signal } : {}),\n });\n return;\n } catch (error) {\n if (!(error instanceof TransportConflict)) throw error;\n }\n }\n throw new Error(\"Storage reservation contention limit exceeded\");\n }\n try {\n await update(false);\n } catch (error) {\n recordRecovery(error, { reservation: id });\n throw error;\n }\n let released = false;\n const release = async () => {\n if (released) return;\n await update(true);\n released = true;\n };\n return {\n id,\n repository,\n reserveBytes: options.reserveBytes,\n release,\n [Symbol.asyncDispose]: release,\n };\n}\n"]}
|
|
@@ -1,4 +1,25 @@
|
|
|
1
|
+
import type { LocalProcessIdentity } from "./git/process-identity.types.ts";
|
|
2
|
+
export interface StorageReservationRecord {
|
|
3
|
+
readonly bytes: number;
|
|
4
|
+
readonly owner?: {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly host: string;
|
|
7
|
+
readonly pid: number;
|
|
8
|
+
readonly createdAt: string;
|
|
9
|
+
readonly repository: string;
|
|
10
|
+
readonly identity?: LocalProcessIdentity;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
1
13
|
export interface ReservationLedger {
|
|
2
|
-
readonly format:
|
|
3
|
-
readonly reservations: Readonly<Record<string,
|
|
14
|
+
readonly format: 2;
|
|
15
|
+
readonly reservations: Readonly<Record<string, StorageReservationRecord>>;
|
|
16
|
+
}
|
|
17
|
+
export interface StorageReservationInspection {
|
|
18
|
+
readonly revision?: string;
|
|
19
|
+
readonly reservations: Readonly<Record<string, StorageReservationRecord>>;
|
|
20
|
+
}
|
|
21
|
+
export interface StorageReservationRecoveryOptions {
|
|
22
|
+
readonly id: string;
|
|
23
|
+
readonly revision: string;
|
|
24
|
+
readonly processesStopped: true;
|
|
4
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport-reservations.types.js","sourceRoot":"","sources":["../../src/infrastructure/transport-reservations.types.ts"],"names":[],"mappings":"","sourcesContent":["
|
|
1
|
+
{"version":3,"file":"transport-reservations.types.js","sourceRoot":"","sources":["../../src/infrastructure/transport-reservations.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { LocalProcessIdentity } from \"./git/process-identity.types.ts\";\n\nexport interface StorageReservationRecord {\n readonly bytes: number;\n readonly owner?: {\n readonly id: string;\n readonly host: string;\n readonly pid: number;\n readonly createdAt: string;\n readonly repository: string;\n readonly identity?: LocalProcessIdentity;\n };\n}\n\nexport interface ReservationLedger {\n readonly format: 2;\n readonly reservations: Readonly<Record<string, StorageReservationRecord>>;\n}\n\nexport interface StorageReservationInspection {\n readonly revision?: string;\n readonly reservations: Readonly<Record<string, StorageReservationRecord>>;\n}\n\nexport interface StorageReservationRecoveryOptions {\n readonly id: string;\n readonly revision: string;\n readonly processesStopped: true;\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TriggerPayloadError } from "../domain/trigger-payload.js";
|
|
1
2
|
import { createServer } from "node:http";
|
|
2
3
|
import { triggerQueueRequest } from "../domain/trigger-job.js";
|
|
3
4
|
import { triggerDefaultMaxBytes, triggerMaxBytes, triggerPathPattern, } from "../domain/trigger.constants.js";
|
|
@@ -80,8 +81,9 @@ export async function serveTriggers(options) {
|
|
|
80
81
|
event = await route.source.verify(request, Date.now());
|
|
81
82
|
}
|
|
82
83
|
catch (error) {
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
const payload = error instanceof TriggerPayloadError;
|
|
85
|
+
report(error, { path: route.path, stage: payload ? "decode" : "verify" });
|
|
86
|
+
return { status: payload ? 400 : 401 };
|
|
85
87
|
}
|
|
86
88
|
const failure = { path: route.path, delivery: event.delivery };
|
|
87
89
|
const reply = (outcome, job) => route.source.reply?.(outcome, job) ?? defaultReply(outcome, job);
|
|
@@ -110,14 +112,14 @@ export async function serveTriggers(options) {
|
|
|
110
112
|
headersTimeout: triggerHttpTimeoutMs,
|
|
111
113
|
maxHeaderSize: triggerHttpMaxHeaderBytes,
|
|
112
114
|
}, async (request, response) => {
|
|
113
|
-
const path = new URL(request.url ?? "/", "http://trigger").pathname;
|
|
114
|
-
const route = routes.get(path);
|
|
115
|
-
if (!route || request.method !== "POST") {
|
|
116
|
-
request.resume();
|
|
117
|
-
send(response, { status: route ? 405 : 404 });
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
115
|
try {
|
|
116
|
+
const path = new URL(request.url ?? "/", "http://trigger").pathname;
|
|
117
|
+
const route = routes.get(path);
|
|
118
|
+
if (!route || request.method !== "POST") {
|
|
119
|
+
request.resume();
|
|
120
|
+
send(response, { status: route ? 405 : 404 });
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
121
123
|
const content = await body(request, limit);
|
|
122
124
|
send(response, await handle(route, {
|
|
123
125
|
method: request.method,
|
|
@@ -127,6 +129,7 @@ export async function serveTriggers(options) {
|
|
|
127
129
|
}));
|
|
128
130
|
}
|
|
129
131
|
catch (error) {
|
|
132
|
+
request.resume();
|
|
130
133
|
response.setHeader("connection", "close");
|
|
131
134
|
send(response, {
|
|
132
135
|
status: error instanceof RequestTooLarge ? 413 : 400,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trigger-server.js","sourceRoot":"","sources":["../../src/infrastructure/trigger-server.ts"],"names":[],"mappings":"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","sourcesContent":["import { createServer } from \"node:http\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { triggerQueueRequest } from \"../domain/trigger-job.ts\";\nimport {\n triggerDefaultMaxBytes,\n triggerMaxBytes,\n triggerPathPattern,\n} from \"../domain/trigger.constants.ts\";\nimport type {\n TriggerEvent,\n TriggerHttpRequest,\n TriggerOutcome,\n TriggerReply,\n} from \"../domain/trigger.types.ts\";\nimport {\n triggerHttpMaxHeaderBytes,\n triggerHttpTimeoutMs,\n} from \"./trigger-server.constants.ts\";\nimport type {\n TriggerFailure,\n TriggerRoute,\n TriggerServer,\n TriggerServerOptions,\n} from \"./trigger-server.types.ts\";\n\nclass RequestTooLarge extends Error {}\n\nfunction routeTable(routes: readonly TriggerRoute[]) {\n if (!Array.isArray(routes) || !routes.length)\n throw new Error(\"serveTriggers() requires at least one route\");\n const table = new Map<string, TriggerRoute>();\n for (const route of routes) {\n if (!triggerPathPattern.test(route.path) || table.has(route.path))\n throw new Error(`Invalid or duplicate trigger path: ${route.path}`);\n if (\n typeof route.source?.verify !== \"function\" ||\n typeof route.on !== \"function\"\n )\n throw new Error(`Trigger route ${route.path} requires a source and on()`);\n table.set(route.path, route);\n }\n return table;\n}\n\nfunction bodyLimit(value: number | undefined): number {\n const limit = value ?? triggerDefaultMaxBytes;\n if (!Number.isSafeInteger(limit) || limit <= 0 || limit > triggerMaxBytes)\n throw new Error(\"Trigger body limit must be between 1 byte and 25 MiB\");\n return limit;\n}\n\nasync function body(request: IncomingMessage, limit: number) {\n const declared = Number(request.headers[\"content-length\"] ?? 0);\n if (declared > limit) throw new RequestTooLarge();\n const chunks: Buffer[] = [];\n let size = 0;\n for await (const chunk of request) {\n const bytes: Buffer = chunk;\n size += bytes.byteLength;\n if (size > limit) throw new RequestTooLarge();\n chunks.push(bytes);\n }\n return Buffer.concat(chunks);\n}\n\nfunction headers(request: IncomingMessage) {\n return Object.fromEntries(\n Object.entries(request.headers).map(([name, value]) => [\n name,\n Array.isArray(value) ? value.join(\", \") : value,\n ]),\n );\n}\n\nfunction send(response: ServerResponse, reply: TriggerReply) {\n response\n .writeHead(reply.status, {\n \"cache-control\": \"no-store\",\n ...(reply.contentType ? { \"content-type\": reply.contentType } : {}),\n })\n .end(reply.body);\n}\n\nfunction defaultReply(outcome: TriggerOutcome, job?: string): TriggerReply {\n if (outcome === \"ignored\") return { status: 204 };\n return {\n status: 202,\n contentType: \"application/json\",\n body: JSON.stringify({ job }),\n };\n}\n\n/** Serve verified webhooks and publish the jobs their routes select. */\nexport async function serveTriggers(\n options: TriggerServerOptions,\n): Promise<TriggerServer> {\n const routes = routeTable(options.routes);\n const limit = bodyLimit(options.maxBytes);\n function report(error: unknown, failure: TriggerFailure) {\n try {\n options.onError?.(error, failure);\n } catch {\n /* Observer failures must not change responses. */\n }\n }\n async function handle(\n route: TriggerRoute,\n request: TriggerHttpRequest,\n ): Promise<TriggerReply> {\n let event: TriggerEvent;\n try {\n event = await route.source.verify(request, Date.now());\n } catch (error) {\n report(error, { path: route.path, stage: \"verify\" });\n return { status: 401 };\n }\n const failure = { path: route.path, delivery: event.delivery };\n const reply = (outcome: TriggerOutcome, job?: string) =>\n route.source.reply?.(outcome, job) ?? defaultReply(outcome, job);\n let queued;\n try {\n const job = await route.on(event);\n if (job === undefined) return reply(\"ignored\");\n queued = triggerQueueRequest(\n `trigger:${route.path}:${event.delivery}`,\n job,\n );\n } catch (error) {\n report(error, { ...failure, stage: \"route\" });\n return { status: 500 };\n }\n try {\n await options.queue.enqueue(queued);\n } catch (error) {\n report(error, { ...failure, stage: \"enqueue\" });\n return { status: 503 };\n }\n return reply(\"accepted\", queued.id);\n }\n const server = createServer(\n {\n requestTimeout: triggerHttpTimeoutMs,\n headersTimeout: triggerHttpTimeoutMs,\n maxHeaderSize: triggerHttpMaxHeaderBytes,\n },\n async (request, response) => {\n const path = new URL(request.url ?? \"/\", \"http://trigger\").pathname;\n const route = routes.get(path);\n if (!route || request.method !== \"POST\") {\n request.resume();\n send(response, { status: route ? 405 : 404 });\n return;\n }\n try {\n const content = await body(request, limit);\n send(\n response,\n await handle(route, {\n method: request.method,\n path,\n headers: headers(request),\n body: content,\n }),\n );\n } catch (error) {\n response.setHeader(\"connection\", \"close\");\n send(response, {\n status: error instanceof RequestTooLarge ? 413 : 400,\n });\n }\n },\n );\n server.setTimeout(triggerHttpTimeoutMs, (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(\"Trigger 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}\n"]}
|
|
1
|
+
{"version":3,"file":"trigger-server.js","sourceRoot":"","sources":["../../src/infrastructure/trigger-server.ts"],"names":[],"mappings":"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","sourcesContent":["import { TriggerPayloadError } from \"../domain/trigger-payload.ts\";\nimport { createServer } from \"node:http\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { triggerQueueRequest } from \"../domain/trigger-job.ts\";\nimport {\n triggerDefaultMaxBytes,\n triggerMaxBytes,\n triggerPathPattern,\n} from \"../domain/trigger.constants.ts\";\nimport type {\n TriggerEvent,\n TriggerHttpRequest,\n TriggerOutcome,\n TriggerReply,\n} from \"../domain/trigger.types.ts\";\nimport {\n triggerHttpMaxHeaderBytes,\n triggerHttpTimeoutMs,\n} from \"./trigger-server.constants.ts\";\nimport type {\n TriggerFailure,\n TriggerRoute,\n TriggerServer,\n TriggerServerOptions,\n} from \"./trigger-server.types.ts\";\n\nclass RequestTooLarge extends Error {}\n\nfunction routeTable(routes: readonly TriggerRoute[]) {\n if (!Array.isArray(routes) || !routes.length)\n throw new Error(\"serveTriggers() requires at least one route\");\n const table = new Map<string, TriggerRoute>();\n for (const route of routes) {\n if (!triggerPathPattern.test(route.path) || table.has(route.path))\n throw new Error(`Invalid or duplicate trigger path: ${route.path}`);\n if (\n typeof route.source?.verify !== \"function\" ||\n typeof route.on !== \"function\"\n )\n throw new Error(`Trigger route ${route.path} requires a source and on()`);\n table.set(route.path, route);\n }\n return table;\n}\n\nfunction bodyLimit(value: number | undefined): number {\n const limit = value ?? triggerDefaultMaxBytes;\n if (!Number.isSafeInteger(limit) || limit <= 0 || limit > triggerMaxBytes)\n throw new Error(\"Trigger body limit must be between 1 byte and 25 MiB\");\n return limit;\n}\n\nasync function body(request: IncomingMessage, limit: number) {\n const declared = Number(request.headers[\"content-length\"] ?? 0);\n if (declared > limit) throw new RequestTooLarge();\n const chunks: Buffer[] = [];\n let size = 0;\n for await (const chunk of request) {\n const bytes: Buffer = chunk;\n size += bytes.byteLength;\n if (size > limit) throw new RequestTooLarge();\n chunks.push(bytes);\n }\n return Buffer.concat(chunks);\n}\n\nfunction headers(request: IncomingMessage) {\n return Object.fromEntries(\n Object.entries(request.headers).map(([name, value]) => [\n name,\n Array.isArray(value) ? value.join(\", \") : value,\n ]),\n );\n}\n\nfunction send(response: ServerResponse, reply: TriggerReply) {\n response\n .writeHead(reply.status, {\n \"cache-control\": \"no-store\",\n ...(reply.contentType ? { \"content-type\": reply.contentType } : {}),\n })\n .end(reply.body);\n}\n\nfunction defaultReply(outcome: TriggerOutcome, job?: string): TriggerReply {\n if (outcome === \"ignored\") return { status: 204 };\n return {\n status: 202,\n contentType: \"application/json\",\n body: JSON.stringify({ job }),\n };\n}\n\n/** Serve verified webhooks and publish the jobs their routes select. */\nexport async function serveTriggers(\n options: TriggerServerOptions,\n): Promise<TriggerServer> {\n const routes = routeTable(options.routes);\n const limit = bodyLimit(options.maxBytes);\n function report(error: unknown, failure: TriggerFailure) {\n try {\n options.onError?.(error, failure);\n } catch {\n /* Observer failures must not change responses. */\n }\n }\n async function handle(\n route: TriggerRoute,\n request: TriggerHttpRequest,\n ): Promise<TriggerReply> {\n let event: TriggerEvent;\n try {\n event = await route.source.verify(request, Date.now());\n } catch (error) {\n const payload = error instanceof TriggerPayloadError;\n report(error, { path: route.path, stage: payload ? \"decode\" : \"verify\" });\n return { status: payload ? 400 : 401 };\n }\n const failure = { path: route.path, delivery: event.delivery };\n const reply = (outcome: TriggerOutcome, job?: string) =>\n route.source.reply?.(outcome, job) ?? defaultReply(outcome, job);\n let queued;\n try {\n const job = await route.on(event);\n if (job === undefined) return reply(\"ignored\");\n queued = triggerQueueRequest(\n `trigger:${route.path}:${event.delivery}`,\n job,\n );\n } catch (error) {\n report(error, { ...failure, stage: \"route\" });\n return { status: 500 };\n }\n try {\n await options.queue.enqueue(queued);\n } catch (error) {\n report(error, { ...failure, stage: \"enqueue\" });\n return { status: 503 };\n }\n return reply(\"accepted\", queued.id);\n }\n const server = createServer(\n {\n requestTimeout: triggerHttpTimeoutMs,\n headersTimeout: triggerHttpTimeoutMs,\n maxHeaderSize: triggerHttpMaxHeaderBytes,\n },\n async (request, response) => {\n try {\n const path = new URL(request.url ?? \"/\", \"http://trigger\").pathname;\n const route = routes.get(path);\n if (!route || request.method !== \"POST\") {\n request.resume();\n send(response, { status: route ? 405 : 404 });\n return;\n }\n const content = await body(request, limit);\n send(\n response,\n await handle(route, {\n method: request.method,\n path,\n headers: headers(request),\n body: content,\n }),\n );\n } catch (error) {\n request.resume();\n response.setHeader(\"connection\", \"close\");\n send(response, {\n status: error instanceof RequestTooLarge ? 413 : 400,\n });\n }\n },\n );\n server.setTimeout(triggerHttpTimeoutMs, (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(\"Trigger 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}\n"]}
|
|
@@ -10,7 +10,7 @@ export interface TriggerRoute {
|
|
|
10
10
|
}
|
|
11
11
|
export interface TriggerFailure {
|
|
12
12
|
readonly path: string;
|
|
13
|
-
readonly stage: "verify" | "route" | "enqueue";
|
|
13
|
+
readonly stage: "verify" | "decode" | "route" | "enqueue";
|
|
14
14
|
readonly delivery?: string;
|
|
15
15
|
}
|
|
16
16
|
export interface TriggerServerOptions {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trigger-server.types.js","sourceRoot":"","sources":["../../src/infrastructure/trigger-server.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { TaskQueue } from \"../domain/task-queue.types.ts\";\nimport type { TriggerJob } from \"../domain/trigger-job.types.ts\";\nimport type { TriggerEvent, TriggerSource } from \"../domain/trigger.types.ts\";\n\nexport interface TriggerRoute {\n /** Exact request path, such as `/github`; part of each job identifier. */\n readonly path: string;\n readonly source: TriggerSource;\n /** Maps a verified event to a job, or `undefined` to ignore it; must return promptly. */\n on(\n event: TriggerEvent,\n ): TriggerJob | undefined | Promise<TriggerJob | undefined>;\n}\n\nexport interface TriggerFailure {\n readonly path: string;\n readonly stage: \"verify\" | \"route\" | \"enqueue\";\n readonly delivery?: string;\n}\n\nexport interface TriggerServerOptions {\n readonly queue: TaskQueue;\n readonly routes: readonly TriggerRoute[];\n /** Defaults to 127.0.0.1; expose through a TLS-terminating proxy. */\n readonly host?: string;\n readonly port?: number;\n /** Request body limit; defaults to 1 MiB, at most 25 MiB. */\n readonly maxBytes?: number;\n /** Observes rejected or failed requests; never receives secrets. */\n readonly onError?: (error: unknown, failure: TriggerFailure) => void;\n}\n\nexport interface TriggerServer {\n readonly url: string;\n close(): Promise<void>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"trigger-server.types.js","sourceRoot":"","sources":["../../src/infrastructure/trigger-server.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { TaskQueue } from \"../domain/task-queue.types.ts\";\nimport type { TriggerJob } from \"../domain/trigger-job.types.ts\";\nimport type { TriggerEvent, TriggerSource } from \"../domain/trigger.types.ts\";\n\nexport interface TriggerRoute {\n /** Exact request path, such as `/github`; part of each job identifier. */\n readonly path: string;\n readonly source: TriggerSource;\n /** Maps a verified event to a job, or `undefined` to ignore it; must return promptly. */\n on(\n event: TriggerEvent,\n ): TriggerJob | undefined | Promise<TriggerJob | undefined>;\n}\n\nexport interface TriggerFailure {\n readonly path: string;\n readonly stage: \"verify\" | \"decode\" | \"route\" | \"enqueue\";\n readonly delivery?: string;\n}\n\nexport interface TriggerServerOptions {\n readonly queue: TaskQueue;\n readonly routes: readonly TriggerRoute[];\n /** Defaults to 127.0.0.1; expose through a TLS-terminating proxy. */\n readonly host?: string;\n readonly port?: number;\n /** Request body limit; defaults to 1 MiB, at most 25 MiB. */\n readonly maxBytes?: number;\n /** Observes rejected or failed requests; never receives secrets. */\n readonly onError?: (error: unknown, failure: TriggerFailure) => void;\n}\n\nexport interface TriggerServer {\n readonly url: string;\n close(): Promise<void>;\n}\n"]}
|
|
@@ -1 +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"]}
|
|
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;AAC3D,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAC,CAAC","sourcesContent":["export const workflowCheckpointMaxBytes = 16 * 1024 * 1024;\nexport const workflowCheckpointReleaseAttempts = 2;\n"]}
|
|
@@ -2,5 +2,6 @@ import { homedir, tmpdir, userInfo } from "node:os";
|
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
export const workspaceLocksDirectory = join(tmpdir(), `outpost-path-locks-${createHash("sha256").update(`${userInfo().username}:${homedir()}`).digest("hex").slice(0, 24)}`);
|
|
5
|
-
export const
|
|
5
|
+
export const workspaceRegistryStaleMs = 10_000;
|
|
6
|
+
export const workspaceRegistryPendingDeleteAttempts = 50;
|
|
6
7
|
//# sourceMappingURL=workspace-lock.constants.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-lock.constants.js","sourceRoot":"","sources":["../../src/infrastructure/workspace-lock.constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CACzC,MAAM,EAAE,EACR,sBAAsB,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC,QAAQ,IAAI,OAAO,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CACtH,CAAC;AACF,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"workspace-lock.constants.js","sourceRoot":"","sources":["../../src/infrastructure/workspace-lock.constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CACzC,MAAM,EAAE,EACR,sBAAsB,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC,QAAQ,IAAI,OAAO,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CACtH,CAAC;AACF,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAC/C,MAAM,CAAC,MAAM,sCAAsC,GAAG,EAAE,CAAC","sourcesContent":["import { homedir, tmpdir, userInfo } from \"node:os\";\nimport { createHash } from \"node:crypto\";\nimport { join } from \"node:path\";\n\nexport const workspaceLocksDirectory = join(\n tmpdir(),\n `outpost-path-locks-${createHash(\"sha256\").update(`${userInfo().username}:${homedir()}`).digest(\"hex\").slice(0, 24)}`,\n);\nexport const workspaceRegistryStaleMs = 10_000;\nexport const workspaceRegistryPendingDeleteAttempts = 50;\n"]}
|
|
@@ -4,7 +4,7 @@ import { dirname, join, resolve } from "node:path";
|
|
|
4
4
|
import { setTimeout } from "node:timers/promises";
|
|
5
5
|
import { invariant } from "../domain/errors.js";
|
|
6
6
|
import { inside } from "./files.js";
|
|
7
|
-
import {
|
|
7
|
+
import { workspaceLocksDirectory, workspaceRegistryPendingDeleteAttempts, workspaceRegistryStaleMs, } from "./workspace-lock.constants.js";
|
|
8
8
|
import { readInspectionFile } from "./inspection-file.js";
|
|
9
9
|
export async function canonicalWorkspacePath(value) {
|
|
10
10
|
const path = resolve(value);
|
|
@@ -25,26 +25,57 @@ async function withRegistry(action) {
|
|
|
25
25
|
!info.isSymbolicLink() &&
|
|
26
26
|
(process.getuid === undefined || info.uid === process.getuid()), "Unsafe workspace lock registry");
|
|
27
27
|
const gate = join(workspaceLocksDirectory, "gate");
|
|
28
|
-
|
|
28
|
+
let observed;
|
|
29
|
+
let since = Date.now();
|
|
30
|
+
let pendingDeletes = 0;
|
|
31
|
+
for (;;) {
|
|
29
32
|
try {
|
|
30
33
|
await mkdir(gate, { mode: 0o700 });
|
|
31
34
|
}
|
|
32
35
|
catch (error) {
|
|
36
|
+
if (pendingDeletion(error) &&
|
|
37
|
+
++pendingDeletes < workspaceRegistryPendingDeleteAttempts) {
|
|
38
|
+
await setTimeout(10);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
33
41
|
if (!(error instanceof Error &&
|
|
34
42
|
"code" in error &&
|
|
35
43
|
error.code === "EEXIST"))
|
|
36
44
|
throw error;
|
|
37
|
-
|
|
45
|
+
pendingDeletes = 0;
|
|
46
|
+
// A gate that keeps changing belongs to live holders; only an unchanged one is reported.
|
|
47
|
+
const current = await gateInstance(gate);
|
|
48
|
+
if (current !== observed)
|
|
49
|
+
since = Date.now();
|
|
50
|
+
observed = current;
|
|
51
|
+
if (current && Date.now() - since >= workspaceRegistryStaleMs)
|
|
52
|
+
throw new Error("Workspace lock registry is busy; inspect abandoned ownership before recovery");
|
|
53
|
+
await setTimeout(5 + Math.random() * 20);
|
|
38
54
|
continue;
|
|
39
55
|
}
|
|
40
56
|
try {
|
|
41
57
|
return await action();
|
|
42
58
|
}
|
|
43
59
|
finally {
|
|
44
|
-
await rm(gate, { recursive: true });
|
|
60
|
+
await rm(gate, { recursive: true, maxRetries: 5 });
|
|
45
61
|
}
|
|
46
62
|
}
|
|
47
|
-
|
|
63
|
+
}
|
|
64
|
+
async function gateInstance(gate) {
|
|
65
|
+
const info = await lstat(gate, { bigint: true }).catch((error) => {
|
|
66
|
+
if ((error instanceof Error && "code" in error && error.code === "ENOENT") ||
|
|
67
|
+
pendingDeletion(error))
|
|
68
|
+
return undefined;
|
|
69
|
+
throw error;
|
|
70
|
+
});
|
|
71
|
+
return info && `${info.dev}:${info.ino}:${info.birthtimeNs}:${info.ctimeNs}`;
|
|
72
|
+
}
|
|
73
|
+
// Windows reports EPERM while a just-released gate is pending deletion.
|
|
74
|
+
function pendingDeletion(error) {
|
|
75
|
+
return (process.platform === "win32" &&
|
|
76
|
+
error instanceof Error &&
|
|
77
|
+
"code" in error &&
|
|
78
|
+
error.code === "EPERM");
|
|
48
79
|
}
|
|
49
80
|
function parseLock(value) {
|
|
50
81
|
invariant(value &&
|
|
@@ -144,11 +175,18 @@ async function acquireWorkspacePath(value, writable, excludedDirectories = []) {
|
|
|
144
175
|
if (existing.excludedDirectories?.some((excluded) => inside(excluded, directory)) ||
|
|
145
176
|
excludedDirectories.some((excluded) => inside(excluded, existing.directory)))
|
|
146
177
|
continue;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
178
|
+
if (!(writable || existing.writable))
|
|
179
|
+
continue;
|
|
180
|
+
// Recorded inodes count only while the locked path still resolves to them; deleted ones get reused.
|
|
181
|
+
const current = await pathIdentities(existing.directory);
|
|
182
|
+
const identity = containsIdentity(current.identity ? [current.identity] : [], existing.identity)
|
|
183
|
+
? existing.identity
|
|
184
|
+
: undefined;
|
|
185
|
+
const ancestors = existing.ancestors?.filter((entry) => containsIdentity(current.ancestors, entry));
|
|
186
|
+
invariant(!(inside(directory, existing.directory) ||
|
|
187
|
+
inside(existing.directory, directory) ||
|
|
188
|
+
containsIdentity(identities.ancestors, identity) ||
|
|
189
|
+
containsIdentity(ancestors, identities.identity)), "Workspace path overlaps an active writer");
|
|
152
190
|
}
|
|
153
191
|
await writeFile(path, JSON.stringify({
|
|
154
192
|
id,
|