@wardby/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +131 -0
- package/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +282 -0
- package/bin/wardby.js +3 -0
- package/deploy/local/docker-compose.yml +19 -0
- package/dist/claude-coding-worker/driver.d.ts +70 -0
- package/dist/claude-coding-worker/driver.js +128 -0
- package/dist/claude-coding-worker/main.d.ts +2 -0
- package/dist/claude-coding-worker/main.js +41 -0
- package/dist/claude-coding-worker/sdk.d.ts +4 -0
- package/dist/claude-coding-worker/sdk.js +43 -0
- package/dist/claude-coding-worker/tool-relay.d.ts +1 -0
- package/dist/claude-coding-worker/tool-relay.js +9 -0
- package/dist/cli-help.d.ts +1 -0
- package/dist/cli-help.js +20 -0
- package/dist/cli.d.ts +18 -0
- package/dist/cli.js +629 -0
- package/dist/coding/observability.d.ts +59 -0
- package/dist/coding/observability.js +77 -0
- package/dist/coding/profile.d.ts +88 -0
- package/dist/coding/profile.js +137 -0
- package/dist/coding/protocol.d.ts +345 -0
- package/dist/coding/protocol.js +445 -0
- package/dist/coding/provider.d.ts +4 -0
- package/dist/coding/provider.js +18 -0
- package/dist/coding-proxy/main.d.ts +1 -0
- package/dist/coding-proxy/main.js +51 -0
- package/dist/coding-worker/artifact.d.ts +16 -0
- package/dist/coding-worker/artifact.js +37 -0
- package/dist/coding-worker/driver.d.ts +46 -0
- package/dist/coding-worker/driver.js +158 -0
- package/dist/coding-worker/errors.d.ts +1 -0
- package/dist/coding-worker/errors.js +23 -0
- package/dist/coding-worker/isolation-probe.d.ts +1 -0
- package/dist/coding-worker/isolation-probe.js +146 -0
- package/dist/coding-worker/keeper.d.ts +4 -0
- package/dist/coding-worker/keeper.js +29 -0
- package/dist/coding-worker/main.d.ts +2 -0
- package/dist/coding-worker/main.js +43 -0
- package/dist/coding-worker/sdk.d.ts +26 -0
- package/dist/coding-worker/sdk.js +28 -0
- package/dist/coding-worker/types.d.ts +64 -0
- package/dist/coding-worker/types.js +1 -0
- package/dist/config/providers.d.ts +158 -0
- package/dist/config/providers.js +162 -0
- package/dist/core/budget-groups.d.ts +72 -0
- package/dist/core/budget-groups.js +149 -0
- package/dist/core/budget.d.ts +63 -0
- package/dist/core/budget.js +69 -0
- package/dist/core/coding-queue.d.ts +32 -0
- package/dist/core/coding-queue.js +54 -0
- package/dist/core/cron.d.ts +31 -0
- package/dist/core/cron.js +43 -0
- package/dist/core/datastores.d.ts +41 -0
- package/dist/core/datastores.js +105 -0
- package/dist/core/db.d.ts +2 -0
- package/dist/core/db.js +2 -0
- package/dist/core/dispatch.d.ts +81 -0
- package/dist/core/dispatch.js +184 -0
- package/dist/core/engine-native.d.ts +29 -0
- package/dist/core/engine-native.js +259 -0
- package/dist/core/http-runtime.d.ts +7 -0
- package/dist/core/http-runtime.js +101 -0
- package/dist/core/lease.d.ts +13 -0
- package/dist/core/lease.js +22 -0
- package/dist/core/logger.d.ts +13 -0
- package/dist/core/logger.js +45 -0
- package/dist/core/memory-tools.d.ts +11 -0
- package/dist/core/memory-tools.js +122 -0
- package/dist/core/reconciler.d.ts +45 -0
- package/dist/core/reconciler.js +152 -0
- package/dist/core/runner.d.ts +87 -0
- package/dist/core/runner.js +529 -0
- package/dist/core/scheduler.d.ts +47 -0
- package/dist/core/scheduler.js +121 -0
- package/dist/core/secrets.d.ts +46 -0
- package/dist/core/secrets.js +100 -0
- package/dist/core/subagent-memory-tools.d.ts +18 -0
- package/dist/core/subagent-memory-tools.js +121 -0
- package/dist/core/timing.d.ts +7 -0
- package/dist/core/timing.js +7 -0
- package/dist/core/webhooks.d.ts +23 -0
- package/dist/core/webhooks.js +113 -0
- package/dist/env.d.ts +11 -0
- package/dist/env.js +13 -0
- package/dist/import/budgets.d.ts +16 -0
- package/dist/import/budgets.js +21 -0
- package/dist/import/bundle.d.ts +16 -0
- package/dist/import/bundle.js +61 -0
- package/dist/import/cli-args.d.ts +2 -0
- package/dist/import/cli-args.js +44 -0
- package/dist/import/create.d.ts +34 -0
- package/dist/import/create.js +363 -0
- package/dist/import/index.d.ts +25 -0
- package/dist/import/index.js +130 -0
- package/dist/import/model-gate.d.ts +1 -0
- package/dist/import/model-gate.js +3 -0
- package/dist/import/neutral-schema.d.ts +369 -0
- package/dist/import/neutral-schema.js +109 -0
- package/dist/import/preflight.d.ts +41 -0
- package/dist/import/preflight.js +71 -0
- package/dist/import/report.d.ts +5 -0
- package/dist/import/report.js +98 -0
- package/dist/import/tool-scan.d.ts +8 -0
- package/dist/import/tool-scan.js +20 -0
- package/dist/mcp/auth/ownership.d.ts +113 -0
- package/dist/mcp/auth/ownership.js +87 -0
- package/dist/mcp/auth/principal.d.ts +9 -0
- package/dist/mcp/auth/principal.js +9 -0
- package/dist/mcp/auth/resource-server.d.ts +47 -0
- package/dist/mcp/auth/resource-server.js +82 -0
- package/dist/mcp/auth/self-hosted/browser.d.ts +3 -0
- package/dist/mcp/auth/self-hosted/browser.js +273 -0
- package/dist/mcp/auth/self-hosted/cli.d.ts +2 -0
- package/dist/mcp/auth/self-hosted/cli.js +39 -0
- package/dist/mcp/auth/self-hosted/credentials.d.ts +58 -0
- package/dist/mcp/auth/self-hosted/credentials.js +106 -0
- package/dist/mcp/auth/self-hosted/rate-limit.d.ts +13 -0
- package/dist/mcp/auth/self-hosted/rate-limit.js +20 -0
- package/dist/mcp/auth/self-hosted/session.d.ts +36 -0
- package/dist/mcp/auth/self-hosted/session.js +110 -0
- package/dist/mcp/capabilities.d.ts +11 -0
- package/dist/mcp/capabilities.js +10 -0
- package/dist/mcp/context.d.ts +46 -0
- package/dist/mcp/context.js +1 -0
- package/dist/mcp/errors.d.ts +13 -0
- package/dist/mcp/errors.js +22 -0
- package/dist/mcp/index.d.ts +32 -0
- package/dist/mcp/index.js +187 -0
- package/dist/mcp/jsonrpc.d.ts +8 -0
- package/dist/mcp/jsonrpc.js +1 -0
- package/dist/mcp/server.d.ts +107 -0
- package/dist/mcp/server.js +203 -0
- package/dist/mcp/tasks/manager.d.ts +63 -0
- package/dist/mcp/tasks/manager.js +103 -0
- package/dist/mcp/tools/agents.d.ts +2 -0
- package/dist/mcp/tools/agents.js +375 -0
- package/dist/mcp/tools/budget-groups.d.ts +2 -0
- package/dist/mcp/tools/budget-groups.js +136 -0
- package/dist/mcp/tools/datastore.d.ts +2 -0
- package/dist/mcp/tools/datastore.js +217 -0
- package/dist/mcp/tools/memory.d.ts +3 -0
- package/dist/mcp/tools/memory.js +60 -0
- package/dist/mcp/tools/models.d.ts +8 -0
- package/dist/mcp/tools/models.js +15 -0
- package/dist/mcp/tools/runs.d.ts +2 -0
- package/dist/mcp/tools/runs.js +61 -0
- package/dist/mcp/tools/scheduling.d.ts +2 -0
- package/dist/mcp/tools/scheduling.js +48 -0
- package/dist/mcp/tools/secret-elicitation-form.d.ts +22 -0
- package/dist/mcp/tools/secret-elicitation-form.js +93 -0
- package/dist/mcp/tools/secret-elicitation-server.d.ts +5 -0
- package/dist/mcp/tools/secret-elicitation-server.js +57 -0
- package/dist/mcp/tools/secret-elicitation.d.ts +38 -0
- package/dist/mcp/tools/secret-elicitation.js +52 -0
- package/dist/mcp/tools/secrets.d.ts +13 -0
- package/dist/mcp/tools/secrets.js +124 -0
- package/dist/mcp/tools/subagents.d.ts +2 -0
- package/dist/mcp/tools/subagents.js +133 -0
- package/dist/mcp/tools/text-result.d.ts +6 -0
- package/dist/mcp/tools/text-result.js +3 -0
- package/dist/mcp/tools/tools.d.ts +2 -0
- package/dist/mcp/tools/tools.js +211 -0
- package/dist/mcp/tools/trigger.d.ts +2 -0
- package/dist/mcp/tools/trigger.js +120 -0
- package/dist/mcp/tools/webhooks.d.ts +2 -0
- package/dist/mcp/tools/webhooks.js +34 -0
- package/dist/mcp/transport/http-limits.d.ts +17 -0
- package/dist/mcp/transport/http-limits.js +92 -0
- package/dist/mcp/transport/stdio.d.ts +23 -0
- package/dist/mcp/transport/stdio.js +6 -0
- package/dist/mcp/transport/streamable-http.d.ts +34 -0
- package/dist/mcp/transport/streamable-http.js +158 -0
- package/dist/mcp/unattended-schedules.d.ts +15 -0
- package/dist/mcp/unattended-schedules.js +21 -0
- package/dist/mcp/webhooks/ingress.d.ts +17 -0
- package/dist/mcp/webhooks/ingress.js +33 -0
- package/dist/observability/config.d.ts +6 -0
- package/dist/observability/config.js +20 -0
- package/dist/observability/metrics-server.d.ts +11 -0
- package/dist/observability/metrics-server.js +47 -0
- package/dist/observability/metrics.d.ts +36 -0
- package/dist/observability/metrics.js +158 -0
- package/dist/providers/auth/authorization-server.d.ts +41 -0
- package/dist/providers/auth/authorization-server.js +1 -0
- package/dist/providers/auth/delegating.d.ts +44 -0
- package/dist/providers/auth/delegating.js +105 -0
- package/dist/providers/auth/index.d.ts +11 -0
- package/dist/providers/auth/index.js +20 -0
- package/dist/providers/auth/release-gate.d.ts +1 -0
- package/dist/providers/auth/release-gate.js +4 -0
- package/dist/providers/auth/self-hosted.d.ts +78 -0
- package/dist/providers/auth/self-hosted.js +377 -0
- package/dist/providers/auth/subject.d.ts +1 -0
- package/dist/providers/auth/subject.js +6 -0
- package/dist/providers/auth/types.d.ts +63 -0
- package/dist/providers/auth/types.js +22 -0
- package/dist/providers/coding-proxy/deny-port.d.ts +5 -0
- package/dist/providers/coding-proxy/deny-port.js +45 -0
- package/dist/providers/coding-proxy/environment-credentials.d.ts +7 -0
- package/dist/providers/coding-proxy/environment-credentials.js +16 -0
- package/dist/providers/coding-proxy/index.d.ts +7 -0
- package/dist/providers/coding-proxy/index.js +7 -0
- package/dist/providers/coding-proxy/memory-ledger.d.ts +17 -0
- package/dist/providers/coding-proxy/memory-ledger.js +103 -0
- package/dist/providers/coding-proxy/metering.d.ts +20 -0
- package/dist/providers/coding-proxy/metering.js +161 -0
- package/dist/providers/coding-proxy/prisma-ledger.d.ts +15 -0
- package/dist/providers/coding-proxy/prisma-ledger.js +213 -0
- package/dist/providers/coding-proxy/proxy.d.ts +75 -0
- package/dist/providers/coding-proxy/proxy.js +721 -0
- package/dist/providers/coding-proxy/runtime.d.ts +18 -0
- package/dist/providers/coding-proxy/runtime.js +39 -0
- package/dist/providers/coding-proxy/secure-fetch.d.ts +9 -0
- package/dist/providers/coding-proxy/secure-fetch.js +72 -0
- package/dist/providers/coding-proxy/server.d.ts +17 -0
- package/dist/providers/coding-proxy/server.js +139 -0
- package/dist/providers/coding-proxy/types.d.ts +99 -0
- package/dist/providers/coding-proxy/types.js +1 -0
- package/dist/providers/datastore/index.d.ts +2 -0
- package/dist/providers/datastore/index.js +2 -0
- package/dist/providers/datastore/postgres.d.ts +20 -0
- package/dist/providers/datastore/postgres.js +130 -0
- package/dist/providers/datastore/scoped.d.ts +10 -0
- package/dist/providers/datastore/scoped.js +46 -0
- package/dist/providers/datastore/types.d.ts +31 -0
- package/dist/providers/datastore/types.js +7 -0
- package/dist/providers/email/types.d.ts +46 -0
- package/dist/providers/email/types.js +8 -0
- package/dist/providers/engine/index.d.ts +1 -0
- package/dist/providers/engine/index.js +1 -0
- package/dist/providers/engine/types.d.ts +67 -0
- package/dist/providers/engine/types.js +16 -0
- package/dist/providers/executor/build.d.ts +6 -0
- package/dist/providers/executor/build.js +15 -0
- package/dist/providers/executor/composition.d.ts +14 -0
- package/dist/providers/executor/composition.js +123 -0
- package/dist/providers/executor/container.d.ts +184 -0
- package/dist/providers/executor/container.js +936 -0
- package/dist/providers/executor/dbos-status.d.ts +50 -0
- package/dist/providers/executor/dbos-status.js +64 -0
- package/dist/providers/executor/dbos.d.ts +53 -0
- package/dist/providers/executor/dbos.js +269 -0
- package/dist/providers/executor/in-process.d.ts +18 -0
- package/dist/providers/executor/in-process.js +38 -0
- package/dist/providers/executor/index.d.ts +8 -0
- package/dist/providers/executor/index.js +8 -0
- package/dist/providers/executor/routing.d.ts +48 -0
- package/dist/providers/executor/routing.js +70 -0
- package/dist/providers/executor/types.d.ts +55 -0
- package/dist/providers/executor/types.js +1 -0
- package/dist/providers/index.d.ts +43 -0
- package/dist/providers/index.js +18 -0
- package/dist/providers/jobs/docker-isolation.d.ts +166 -0
- package/dist/providers/jobs/docker-isolation.js +724 -0
- package/dist/providers/jobs/docker.d.ts +127 -0
- package/dist/providers/jobs/docker.js +1027 -0
- package/dist/providers/jobs/fake-kubernetes-api.d.ts +98 -0
- package/dist/providers/jobs/fake-kubernetes-api.js +142 -0
- package/dist/providers/jobs/fake.d.ts +23 -0
- package/dist/providers/jobs/fake.js +132 -0
- package/dist/providers/jobs/kubernetes-api.d.ts +60 -0
- package/dist/providers/jobs/kubernetes-api.js +20 -0
- package/dist/providers/jobs/kubernetes-client.d.ts +36 -0
- package/dist/providers/jobs/kubernetes-client.js +171 -0
- package/dist/providers/jobs/kubernetes-dry-run-fixture.d.ts +49 -0
- package/dist/providers/jobs/kubernetes-dry-run-fixture.js +141 -0
- package/dist/providers/jobs/kubernetes-isolation.d.ts +147 -0
- package/dist/providers/jobs/kubernetes-isolation.js +607 -0
- package/dist/providers/jobs/kubernetes-platform.d.ts +177 -0
- package/dist/providers/jobs/kubernetes-platform.js +280 -0
- package/dist/providers/jobs/kubernetes-preflight.d.ts +59 -0
- package/dist/providers/jobs/kubernetes-preflight.js +339 -0
- package/dist/providers/jobs/kubernetes-witness.d.ts +10 -0
- package/dist/providers/jobs/kubernetes-witness.js +193 -0
- package/dist/providers/jobs/kubernetes.d.ts +127 -0
- package/dist/providers/jobs/kubernetes.js +874 -0
- package/dist/providers/jobs/safe-extract.d.ts +9 -0
- package/dist/providers/jobs/safe-extract.js +325 -0
- package/dist/providers/jobs/types.d.ts +78 -0
- package/dist/providers/jobs/types.js +6 -0
- package/dist/providers/jobs/workspace-swap.d.ts +2 -0
- package/dist/providers/jobs/workspace-swap.js +47 -0
- package/dist/providers/llm/anthropic.d.ts +13 -0
- package/dist/providers/llm/anthropic.js +21 -0
- package/dist/providers/llm/bedrock.d.ts +19 -0
- package/dist/providers/llm/bedrock.js +33 -0
- package/dist/providers/llm/claude-messages.d.ts +106 -0
- package/dist/providers/llm/claude-messages.js +157 -0
- package/dist/providers/llm/claude-provider.d.ts +40 -0
- package/dist/providers/llm/claude-provider.js +31 -0
- package/dist/providers/llm/index.d.ts +10 -0
- package/dist/providers/llm/index.js +10 -0
- package/dist/providers/llm/openai.d.ts +23 -0
- package/dist/providers/llm/openai.js +156 -0
- package/dist/providers/llm/pricing-anthropic.d.ts +4 -0
- package/dist/providers/llm/pricing-anthropic.js +30 -0
- package/dist/providers/llm/pricing-bedrock-claude.d.ts +12 -0
- package/dist/providers/llm/pricing-bedrock-claude.js +37 -0
- package/dist/providers/llm/pricing-core.d.ts +26 -0
- package/dist/providers/llm/pricing-core.js +17 -0
- package/dist/providers/llm/pricing.d.ts +30 -0
- package/dist/providers/llm/pricing.js +74 -0
- package/dist/providers/llm/registration.d.ts +8 -0
- package/dist/providers/llm/registration.js +39 -0
- package/dist/providers/llm/routing.d.ts +25 -0
- package/dist/providers/llm/routing.js +32 -0
- package/dist/providers/llm/types.d.ts +85 -0
- package/dist/providers/llm/types.js +12 -0
- package/dist/providers/memory/index.d.ts +2 -0
- package/dist/providers/memory/index.js +2 -0
- package/dist/providers/memory/postgres.d.ts +20 -0
- package/dist/providers/memory/postgres.js +72 -0
- package/dist/providers/memory/types.d.ts +32 -0
- package/dist/providers/memory/types.js +17 -0
- package/dist/providers/secrets/app-key.d.ts +8 -0
- package/dist/providers/secrets/app-key.js +50 -0
- package/dist/providers/secrets/index.d.ts +10 -0
- package/dist/providers/secrets/index.js +13 -0
- package/dist/providers/secrets/transfer-envelope.d.ts +12 -0
- package/dist/providers/secrets/transfer-envelope.js +35 -0
- package/dist/providers/secrets/types.d.ts +18 -0
- package/dist/providers/secrets/types.js +12 -0
- package/dist/providers/storage/types.d.ts +18 -0
- package/dist/providers/storage/types.js +7 -0
- package/dist/providers/vcs/git.d.ts +105 -0
- package/dist/providers/vcs/git.js +710 -0
- package/dist/providers/vcs/github.d.ts +105 -0
- package/dist/providers/vcs/github.js +394 -0
- package/dist/providers/vcs/index.d.ts +6 -0
- package/dist/providers/vcs/index.js +26 -0
- package/dist/providers/vcs/types.d.ts +118 -0
- package/dist/providers/vcs/types.js +1 -0
- package/dist/sandbox/bounded-json.d.ts +2 -0
- package/dist/sandbox/bounded-json.js +36 -0
- package/dist/sandbox/bridge.d.ts +15 -0
- package/dist/sandbox/bridge.js +78 -0
- package/dist/sandbox/eval-core.d.ts +37 -0
- package/dist/sandbox/eval-core.js +159 -0
- package/dist/sandbox/fetch-policy.d.ts +24 -0
- package/dist/sandbox/fetch-policy.js +96 -0
- package/dist/sandbox/generated/zod-to-json-schema.bundle.js +5 -0
- package/dist/sandbox/generated/zod.bundle.js +1 -0
- package/dist/sandbox/host-functions.d.ts +29 -0
- package/dist/sandbox/host-functions.js +168 -0
- package/dist/sandbox/limits.d.ts +39 -0
- package/dist/sandbox/limits.js +39 -0
- package/dist/sandbox/parser-worker/__fixtures__/crash.d.ts +1 -0
- package/dist/sandbox/parser-worker/__fixtures__/crash.js +6 -0
- package/dist/sandbox/parser-worker/__fixtures__/echo.d.ts +1 -0
- package/dist/sandbox/parser-worker/__fixtures__/echo.js +5 -0
- package/dist/sandbox/parser-worker/__fixtures__/reject.d.ts +1 -0
- package/dist/sandbox/parser-worker/__fixtures__/reject.js +5 -0
- package/dist/sandbox/parser-worker/__fixtures__/spin-forever.d.ts +1 -0
- package/dist/sandbox/parser-worker/__fixtures__/spin-forever.js +11 -0
- package/dist/sandbox/parser-worker/pool.d.ts +13 -0
- package/dist/sandbox/parser-worker/pool.js +111 -0
- package/dist/sandbox/parser-worker/worker.d.ts +14 -0
- package/dist/sandbox/parser-worker/worker.js +63 -0
- package/dist/sandbox/pii-redaction.d.ts +1 -0
- package/dist/sandbox/pii-redaction.js +29 -0
- package/dist/sandbox/prelude.d.ts +26 -0
- package/dist/sandbox/prelude.js +408 -0
- package/dist/sandbox/quickjs-module.d.ts +13 -0
- package/dist/sandbox/quickjs-module.js +19 -0
- package/dist/sandbox/run-in-sandbox.d.ts +34 -0
- package/dist/sandbox/run-in-sandbox.js +53 -0
- package/dist/sandbox/safe-fetch.d.ts +26 -0
- package/dist/sandbox/safe-fetch.js +140 -0
- package/dist/sandbox/tool-capabilities.d.ts +66 -0
- package/dist/sandbox/tool-capabilities.js +103 -0
- package/dist/sandbox/zod-params.d.ts +22 -0
- package/dist/sandbox/zod-params.js +60 -0
- package/dist/serve.d.ts +14 -0
- package/dist/serve.js +54 -0
- package/dist/wardby-bin.d.ts +2 -0
- package/dist/wardby-bin.js +20 -0
- package/package.json +123 -0
- package/prisma/migrations/20260905000000_init/migration.sql +34 -0
- package/prisma/migrations/20260905010000_scheduler_durability/migration.sql +31 -0
- package/prisma/migrations/20260905020000_tools_multiturn/migration.sql +47 -0
- package/prisma/migrations/20260905030000_cache_tool_json_schema/migration.sql +13 -0
- package/prisma/migrations/20260906000000_mcp_phase4/migration.sql +115 -0
- package/prisma/migrations/20260906010000_run_final_text/migration.sql +7 -0
- package/prisma/migrations/20260906020000_run_turns/migration.sql +6 -0
- package/prisma/migrations/20260906030000_task_principal_id/migration.sql +5 -0
- package/prisma/migrations/20260906040000_secure_self_hosted_oauth/migration.sql +67 -0
- package/prisma/migrations/20260906050000_phase5_coding_agents/migration.sql +52 -0
- package/prisma/migrations/20260906060000_tool_capability_scoping/migration.sql +22 -0
- package/prisma/migrations/20260906070000_datastore_pii_flag/migration.sql +6 -0
- package/prisma/migrations/20260906080000_secret_elicitation_outcomes/migration.sql +13 -0
- package/prisma/migrations/20260907010000_coding_proxy_ledger/migration.sql +57 -0
- package/prisma/migrations/20260907020000_budget_groups/migration.sql +24 -0
- package/prisma/migrations/20260907030000_coding_webhook_task_override/migration.sql +4 -0
- package/prisma/migrations/20260908010000_run_execution_backend/migration.sql +2 -0
- package/prisma/migrations/20260908020000_coding_run_audit_metadata/migration.sql +7 -0
- package/prisma/migrations/20260910010000_agent_secret_bound_name/migration.sql +16 -0
- package/prisma/migrations/20260911010000_coding_worker_toolchains/migration.sql +5 -0
- package/prisma/migrations/20260912010000_coding_provider_contract/migration.sql +24 -0
- package/prisma/migrations/20260912020000_coding_proxy_protocol/migration.sql +10 -0
- package/prisma/migrations/20260912030000_agent_memory/migration.sql +18 -0
- package/prisma/migrations/20260912040000_named_shared_datastores/migration.sql +68 -0
- package/prisma/migrations/20260913000000_run_trigger_webhook/migration.sql +2 -0
- package/prisma/migrations/20260913010000_agent_sub_agent/migration.sql +32 -0
- package/prisma/migrations/20260913020000_run_task_override/migration.sql +5 -0
- package/prisma/migrations/20260913030000_coding_run_root/migration.sql +11 -0
- package/prisma/migrations/20260922010000_coding_run_queued_at/migration.sql +8 -0
- package/prisma/migrations/20260922020000_coding_workspace_disk/migration.sql +8 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +723 -0
- package/scripts/git-askpass.sh +11 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export function boundedJson(value, maxBytes) {
|
|
2
|
+
const seen = new Set();
|
|
3
|
+
let budget = maxBytes;
|
|
4
|
+
let nodes = 0;
|
|
5
|
+
function visit(v, depth) {
|
|
6
|
+
if (++nodes > 100_000 || depth > 64)
|
|
7
|
+
throw new Error("bridge_structure_limit");
|
|
8
|
+
if (typeof v === "string")
|
|
9
|
+
budget -= Buffer.byteLength(v) + 2;
|
|
10
|
+
else if (v && typeof v === "object") {
|
|
11
|
+
if (seen.has(v))
|
|
12
|
+
throw new Error("bridge_cycle");
|
|
13
|
+
seen.add(v);
|
|
14
|
+
for (const [key, child] of Object.entries(v)) {
|
|
15
|
+
budget -= Buffer.byteLength(key) + 4;
|
|
16
|
+
if (budget < 0)
|
|
17
|
+
throw new Error("bridge_size_limit");
|
|
18
|
+
visit(child, depth + 1);
|
|
19
|
+
}
|
|
20
|
+
seen.delete(v);
|
|
21
|
+
}
|
|
22
|
+
else
|
|
23
|
+
budget -= 8;
|
|
24
|
+
if (budget < 0)
|
|
25
|
+
throw new Error("bridge_size_limit");
|
|
26
|
+
}
|
|
27
|
+
visit(value, 0);
|
|
28
|
+
const json = JSON.stringify(value ?? null);
|
|
29
|
+
if (Buffer.byteLength(json) > maxBytes)
|
|
30
|
+
throw new Error("bridge_size_limit");
|
|
31
|
+
return json;
|
|
32
|
+
}
|
|
33
|
+
export function boundedString(value, maxBytes) {
|
|
34
|
+
if (typeof value !== "string" || Buffer.byteLength(value) > maxBytes)
|
|
35
|
+
throw new Error("bridge_input_limit");
|
|
36
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one generic mechanism for exposing a host-side async capability to
|
|
3
|
+
* sandboxed code. Every host function (fetch, datastore, parsers, sleep,
|
|
4
|
+
* console) is registered through this — centralizing the QuickJS handle
|
|
5
|
+
* lifecycle (a real leak/crash risk if scattered across many call sites; a
|
|
6
|
+
* spike confirmed both proper disposal and rejection propagation with
|
|
7
|
+
* this exact shape) in one place instead of repeating it per capability.
|
|
8
|
+
*
|
|
9
|
+
* Values cross the boundary JSON-serialized: the registered function takes
|
|
10
|
+
* one JSON-string argument and the sandbox-side prelude (prelude.ts)
|
|
11
|
+
* JSON-parses the JSON-string result. A thrown/rejected `impl` becomes a
|
|
12
|
+
* real catchable exception inside the sandbox (QuickJS promise rejection).
|
|
13
|
+
*/
|
|
14
|
+
import type { QuickJSContext, QuickJSRuntime } from "quickjs-emscripten";
|
|
15
|
+
export declare function registerJsonAsyncFunction(context: QuickJSContext, runtime: QuickJSRuntime, name: string, impl: (argsJson: string) => Promise<unknown>, signal?: AbortSignal): void;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one generic mechanism for exposing a host-side async capability to
|
|
3
|
+
* sandboxed code. Every host function (fetch, datastore, parsers, sleep,
|
|
4
|
+
* console) is registered through this — centralizing the QuickJS handle
|
|
5
|
+
* lifecycle (a real leak/crash risk if scattered across many call sites; a
|
|
6
|
+
* spike confirmed both proper disposal and rejection propagation with
|
|
7
|
+
* this exact shape) in one place instead of repeating it per capability.
|
|
8
|
+
*
|
|
9
|
+
* Values cross the boundary JSON-serialized: the registered function takes
|
|
10
|
+
* one JSON-string argument and the sandbox-side prelude (prelude.ts)
|
|
11
|
+
* JSON-parses the JSON-string result. A thrown/rejected `impl` becomes a
|
|
12
|
+
* real catchable exception inside the sandbox (QuickJS promise rejection).
|
|
13
|
+
*/
|
|
14
|
+
import { boundedJson } from "./bounded-json.js";
|
|
15
|
+
import { BRIDGE_INPUT_BYTES, BRIDGE_RESULT_BYTES, MAX_HOST_CALLS, MAX_PENDING_HOST_CALLS } from "./limits.js";
|
|
16
|
+
const budgets = new WeakMap();
|
|
17
|
+
export function registerJsonAsyncFunction(context, runtime, name, impl, signal) {
|
|
18
|
+
const fnHandle = context.newFunction(name, (argHandle) => {
|
|
19
|
+
const budget = budgets.get(runtime) ?? { calls: 0, pending: 0 };
|
|
20
|
+
budgets.set(runtime, budget);
|
|
21
|
+
if (signal?.aborted || ++budget.calls > MAX_HOST_CALLS || budget.pending >= MAX_PENDING_HOST_CALLS)
|
|
22
|
+
return { error: context.newError("bridge_call_limit") };
|
|
23
|
+
if (!argHandle || context.typeof(argHandle) !== "string")
|
|
24
|
+
return { error: context.newError("bridge_input_invalid") };
|
|
25
|
+
const lengthHandle = context.getProp(argHandle, "length");
|
|
26
|
+
const length = context.getNumber(lengthHandle);
|
|
27
|
+
lengthHandle.dispose();
|
|
28
|
+
if (length > BRIDGE_INPUT_BYTES)
|
|
29
|
+
return { error: context.newError("bridge_input_limit") };
|
|
30
|
+
const argsJson = context.getString(argHandle);
|
|
31
|
+
if (Buffer.byteLength(argsJson) > BRIDGE_INPUT_BYTES)
|
|
32
|
+
return { error: context.newError("bridge_input_limit") };
|
|
33
|
+
const deferred = context.newPromise();
|
|
34
|
+
budget.pending++;
|
|
35
|
+
const abort = () => {
|
|
36
|
+
if (deferred.alive)
|
|
37
|
+
deferred.dispose();
|
|
38
|
+
};
|
|
39
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
40
|
+
Promise.resolve()
|
|
41
|
+
.then(() => {
|
|
42
|
+
signal?.throwIfAborted();
|
|
43
|
+
return impl(argsJson);
|
|
44
|
+
})
|
|
45
|
+
.then((value) => {
|
|
46
|
+
if (!deferred.alive)
|
|
47
|
+
return;
|
|
48
|
+
const resultHandle = context.newString(boundedJson(value, BRIDGE_RESULT_BYTES));
|
|
49
|
+
deferred.resolve(resultHandle);
|
|
50
|
+
resultHandle.dispose();
|
|
51
|
+
})
|
|
52
|
+
.catch((err) => {
|
|
53
|
+
if (!deferred.alive)
|
|
54
|
+
return;
|
|
55
|
+
const message = err instanceof Error ? err.message.slice(0, 1024) : "Host function failed.";
|
|
56
|
+
const errorHandle = context.newError(message);
|
|
57
|
+
deferred.reject(errorHandle);
|
|
58
|
+
errorHandle.dispose();
|
|
59
|
+
})
|
|
60
|
+
.finally(() => {
|
|
61
|
+
budget.pending--;
|
|
62
|
+
signal?.removeEventListener("abort", abort);
|
|
63
|
+
});
|
|
64
|
+
deferred.settled
|
|
65
|
+
.then(() => {
|
|
66
|
+
if (runtime.alive && !signal?.aborted)
|
|
67
|
+
runtime.executePendingJobs();
|
|
68
|
+
})
|
|
69
|
+
.finally(() => {
|
|
70
|
+
if (deferred.alive)
|
|
71
|
+
deferred.dispose();
|
|
72
|
+
})
|
|
73
|
+
.catch(() => { });
|
|
74
|
+
return deferred.handle;
|
|
75
|
+
});
|
|
76
|
+
context.setProp(context.global, name, fnHandle);
|
|
77
|
+
fnHandle.dispose();
|
|
78
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The reusable core: create a fresh runtime + context with resource limits,
|
|
3
|
+
* eval a script that resolves to a JSON string, marshal the result,
|
|
4
|
+
* dispose. Shared by `run-in-sandbox.ts` (installs the full host API for a
|
|
5
|
+
* tool invocation) and `zod-params.ts` (installs nothing — schema
|
|
6
|
+
* compilation/validation is pure computation, no host I/O at all).
|
|
7
|
+
*/
|
|
8
|
+
import type { QuickJSContext, QuickJSRuntime } from "quickjs-emscripten";
|
|
9
|
+
export type SandboxErrorKind = "thrown" | "timeout" | "memory" | "cpu" | "non_serializable";
|
|
10
|
+
export type SandboxResult = {
|
|
11
|
+
ok: true;
|
|
12
|
+
value: unknown;
|
|
13
|
+
} | {
|
|
14
|
+
ok: false;
|
|
15
|
+
errorKind: SandboxErrorKind;
|
|
16
|
+
errorMessage: string;
|
|
17
|
+
};
|
|
18
|
+
export interface SandboxLimits {
|
|
19
|
+
memoryLimitBytes: number;
|
|
20
|
+
maxInterruptChecks: number;
|
|
21
|
+
wallTimeLimitMs: number;
|
|
22
|
+
maxStackSizeBytes: number;
|
|
23
|
+
}
|
|
24
|
+
export declare const DEFAULT_SANDBOX_LIMITS: SandboxLimits;
|
|
25
|
+
/**
|
|
26
|
+
* The script must evaluate to a JSON-string-yielding value (a Promise of a
|
|
27
|
+
* string, per the calling convention both `run-in-sandbox.ts` and
|
|
28
|
+
* `zod-params.ts` use: wrap the real payload in a final `JSON.stringify`
|
|
29
|
+
* inside the sandbox so a serialization failure is itself a catchable
|
|
30
|
+
* sandbox exception, not a host-side surprise).
|
|
31
|
+
*/
|
|
32
|
+
export declare const NON_SERIALIZABLE_MARKER = "__wardby_non_serializable__:";
|
|
33
|
+
export declare function classifyEvalError(dumped: {
|
|
34
|
+
name?: string;
|
|
35
|
+
message?: string;
|
|
36
|
+
}): SandboxResult;
|
|
37
|
+
export declare function evalToJson(code: string, limitsOverride: Partial<SandboxLimits> | undefined, installExtras: (context: QuickJSContext, runtime: QuickJSRuntime, signal: AbortSignal) => void): Promise<SandboxResult>;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The reusable core: create a fresh runtime + context with resource limits,
|
|
3
|
+
* eval a script that resolves to a JSON string, marshal the result,
|
|
4
|
+
* dispose. Shared by `run-in-sandbox.ts` (installs the full host API for a
|
|
5
|
+
* tool invocation) and `zod-params.ts` (installs nothing — schema
|
|
6
|
+
* compilation/validation is pure computation, no host I/O at all).
|
|
7
|
+
*/
|
|
8
|
+
import { getQuickJsModule } from "./quickjs-module.js";
|
|
9
|
+
import { MAX_INTERRUPT_CHECKS, MAX_STACK_SIZE_BYTES, MEMORY_LIMIT_BYTES, WALL_TIME_LIMIT_MS } from "./limits.js";
|
|
10
|
+
import { BRIDGE_RESULT_BYTES } from "./limits.js";
|
|
11
|
+
export const DEFAULT_SANDBOX_LIMITS = {
|
|
12
|
+
memoryLimitBytes: MEMORY_LIMIT_BYTES,
|
|
13
|
+
maxInterruptChecks: MAX_INTERRUPT_CHECKS,
|
|
14
|
+
wallTimeLimitMs: WALL_TIME_LIMIT_MS,
|
|
15
|
+
maxStackSizeBytes: MAX_STACK_SIZE_BYTES,
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* The script must evaluate to a JSON-string-yielding value (a Promise of a
|
|
19
|
+
* string, per the calling convention both `run-in-sandbox.ts` and
|
|
20
|
+
* `zod-params.ts` use: wrap the real payload in a final `JSON.stringify`
|
|
21
|
+
* inside the sandbox so a serialization failure is itself a catchable
|
|
22
|
+
* sandbox exception, not a host-side surprise).
|
|
23
|
+
*/
|
|
24
|
+
export const NON_SERIALIZABLE_MARKER = "__wardby_non_serializable__:";
|
|
25
|
+
function boundedError(context, handle) {
|
|
26
|
+
const result = {};
|
|
27
|
+
for (const key of ["name", "message"]) {
|
|
28
|
+
const value = context.getProp(handle, key);
|
|
29
|
+
if (context.typeof(value) === "string") {
|
|
30
|
+
const size = context.getProp(value, "length");
|
|
31
|
+
const length = context.getNumber(size);
|
|
32
|
+
size.dispose();
|
|
33
|
+
result[key] = length <= 4096 ? context.getString(value) : "Sandbox error text exceeded limit.";
|
|
34
|
+
}
|
|
35
|
+
value.dispose();
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
export function classifyEvalError(dumped) {
|
|
40
|
+
if (dumped.name === "InternalError" && dumped.message === "interrupted") {
|
|
41
|
+
return { ok: false, errorKind: "cpu", errorMessage: "Exceeded the CPU/instruction budget." };
|
|
42
|
+
}
|
|
43
|
+
if (dumped.name === "InternalError" && dumped.message === "out of memory") {
|
|
44
|
+
return { ok: false, errorKind: "memory", errorMessage: "Exceeded the sandbox memory limit." };
|
|
45
|
+
}
|
|
46
|
+
if (dumped.message?.startsWith(NON_SERIALIZABLE_MARKER)) {
|
|
47
|
+
return {
|
|
48
|
+
ok: false,
|
|
49
|
+
errorKind: "non_serializable",
|
|
50
|
+
errorMessage: `Returned a value that could not be JSON-serialized: ${dumped.message.slice(NON_SERIALIZABLE_MARKER.length)}`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
ok: false,
|
|
55
|
+
errorKind: "thrown",
|
|
56
|
+
errorMessage: dumped.message ? `${dumped.name ?? "Error"}: ${dumped.message}` : JSON.stringify(dumped),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export async function evalToJson(code, limitsOverride, installExtras) {
|
|
60
|
+
const limits = { ...DEFAULT_SANDBOX_LIMITS, ...limitsOverride };
|
|
61
|
+
const controller = new AbortController();
|
|
62
|
+
let timer;
|
|
63
|
+
const deadline = Date.now() + limits.wallTimeLimitMs;
|
|
64
|
+
const qjsModule = await getQuickJsModule();
|
|
65
|
+
const runtime = qjsModule.newRuntime();
|
|
66
|
+
runtime.setMemoryLimit(limits.memoryLimitBytes);
|
|
67
|
+
runtime.setMaxStackSize(limits.maxStackSizeBytes);
|
|
68
|
+
let steps = 0;
|
|
69
|
+
runtime.setInterruptHandler(() => {
|
|
70
|
+
steps += 1;
|
|
71
|
+
return steps > limits.maxInterruptChecks || Date.now() >= deadline;
|
|
72
|
+
});
|
|
73
|
+
const context = runtime.newContext();
|
|
74
|
+
let disposed = false;
|
|
75
|
+
const disposeAll = () => {
|
|
76
|
+
if (disposed)
|
|
77
|
+
return;
|
|
78
|
+
disposed = true;
|
|
79
|
+
// Best-effort: if the wall-time race below abandons a still-running
|
|
80
|
+
// evaluation, teardown may not be pristine. Never let it crash the host.
|
|
81
|
+
try {
|
|
82
|
+
context.dispose();
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
/* best-effort */
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
runtime.dispose();
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
/* best-effort */
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
try {
|
|
95
|
+
installExtras(context, runtime, controller.signal);
|
|
96
|
+
const runPromise = (async () => {
|
|
97
|
+
const evalResult = context.evalCode(code);
|
|
98
|
+
if (evalResult.error) {
|
|
99
|
+
const dumped = boundedError(context, evalResult.error);
|
|
100
|
+
evalResult.error.dispose();
|
|
101
|
+
return classifyEvalError(dumped);
|
|
102
|
+
}
|
|
103
|
+
const settledPromise = context.resolvePromise(evalResult.value);
|
|
104
|
+
evalResult.value.dispose();
|
|
105
|
+
runtime.executePendingJobs();
|
|
106
|
+
const settled = await settledPromise;
|
|
107
|
+
if (settled.error) {
|
|
108
|
+
const dumped = boundedError(context, settled.error);
|
|
109
|
+
settled.error.dispose();
|
|
110
|
+
return classifyEvalError(dumped);
|
|
111
|
+
}
|
|
112
|
+
if (context.typeof(settled.value) !== "string") {
|
|
113
|
+
settled.value.dispose();
|
|
114
|
+
throw new Error("bridge_result_invalid");
|
|
115
|
+
}
|
|
116
|
+
const lengthHandle = context.getProp(settled.value, "length");
|
|
117
|
+
const length = context.getNumber(lengthHandle);
|
|
118
|
+
lengthHandle.dispose();
|
|
119
|
+
if (length > BRIDGE_RESULT_BYTES) {
|
|
120
|
+
settled.value.dispose();
|
|
121
|
+
throw new Error("bridge_result_limit");
|
|
122
|
+
}
|
|
123
|
+
const raw = context.getString(settled.value);
|
|
124
|
+
settled.value.dispose();
|
|
125
|
+
if (Buffer.byteLength(raw) > BRIDGE_RESULT_BYTES)
|
|
126
|
+
throw new Error("bridge_result_limit");
|
|
127
|
+
try {
|
|
128
|
+
return { ok: true, value: JSON.parse(raw) };
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return {
|
|
132
|
+
ok: false,
|
|
133
|
+
errorKind: "non_serializable",
|
|
134
|
+
errorMessage: "Returned a value that could not be JSON-serialized.",
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
})();
|
|
138
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
139
|
+
timer = setTimeout(() => resolve({
|
|
140
|
+
ok: false,
|
|
141
|
+
errorKind: "timeout",
|
|
142
|
+
errorMessage: `Exceeded the ${limits.wallTimeLimitMs}ms wall-time limit.`,
|
|
143
|
+
}), limits.wallTimeLimitMs);
|
|
144
|
+
});
|
|
145
|
+
return await Promise.race([runPromise, timeoutPromise]);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
return {
|
|
149
|
+
ok: false,
|
|
150
|
+
errorKind: "thrown",
|
|
151
|
+
errorMessage: err instanceof Error ? err.message : String(err),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
finally {
|
|
155
|
+
clearTimeout(timer);
|
|
156
|
+
controller.abort();
|
|
157
|
+
disposeAll();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type ResolvedAddress = {
|
|
2
|
+
address: string;
|
|
3
|
+
family: number;
|
|
4
|
+
};
|
|
5
|
+
export type Resolver = (hostname: string) => Promise<ResolvedAddress[]>;
|
|
6
|
+
export interface FetchPolicyOptions {
|
|
7
|
+
allowedHosts?: string[];
|
|
8
|
+
allowPrivateHosts?: boolean;
|
|
9
|
+
resolve?: Resolver;
|
|
10
|
+
restrictToAllowedHosts?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare class FetchPolicyError extends Error {
|
|
13
|
+
constructor();
|
|
14
|
+
}
|
|
15
|
+
export declare function isGlobalAddress(address: string): boolean;
|
|
16
|
+
export declare function normalizeHost(host: string): string;
|
|
17
|
+
export declare function parseAllowedHosts(value: string | undefined): string[];
|
|
18
|
+
export declare function resolveDestination(urlString: string, options?: FetchPolicyOptions): Promise<{
|
|
19
|
+
url: URL;
|
|
20
|
+
hostname: string;
|
|
21
|
+
address: string;
|
|
22
|
+
family: number;
|
|
23
|
+
}>;
|
|
24
|
+
export declare function assertFetchDestinationAllowed(url: string, options?: FetchPolicyOptions): Promise<void>;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { isIP } from "node:net";
|
|
2
|
+
import { lookup } from "node:dns/promises";
|
|
3
|
+
export class FetchPolicyError extends Error {
|
|
4
|
+
constructor() {
|
|
5
|
+
super("fetch_destination_blocked");
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
const blockedV4 = [
|
|
9
|
+
["0.0.0.0", 8],
|
|
10
|
+
["10.0.0.0", 8],
|
|
11
|
+
["100.64.0.0", 10],
|
|
12
|
+
["127.0.0.0", 8],
|
|
13
|
+
["169.254.0.0", 16],
|
|
14
|
+
["172.16.0.0", 12],
|
|
15
|
+
["192.0.0.0", 24],
|
|
16
|
+
["192.0.2.0", 24],
|
|
17
|
+
["192.88.99.0", 24],
|
|
18
|
+
["192.168.0.0", 16],
|
|
19
|
+
["198.18.0.0", 15],
|
|
20
|
+
["198.51.100.0", 24],
|
|
21
|
+
["203.0.113.0", 24],
|
|
22
|
+
["224.0.0.0", 4],
|
|
23
|
+
["240.0.0.0", 4],
|
|
24
|
+
];
|
|
25
|
+
function v4(ip) {
|
|
26
|
+
return ip.split(".").reduce((a, b) => (a << 8) + Number(b), 0) >>> 0;
|
|
27
|
+
}
|
|
28
|
+
function v6(ip) {
|
|
29
|
+
const [left, right] = ip.split("::");
|
|
30
|
+
const a = left ? left.split(":") : [];
|
|
31
|
+
const b = right ? right.split(":") : [];
|
|
32
|
+
const groups = ip.includes("::") ? [...a, ...new Array(8 - a.length - b.length).fill("0"), ...b] : a;
|
|
33
|
+
return groups.reduce((n, g) => (n << 16n) + BigInt("0x" + g), 0n);
|
|
34
|
+
}
|
|
35
|
+
export function isGlobalAddress(address) {
|
|
36
|
+
if (isIP(address) === 4)
|
|
37
|
+
return !blockedV4.some(([net, prefix]) => v4(address) >>> (32 - prefix) === v4(net) >>> (32 - prefix));
|
|
38
|
+
if (isIP(address) !== 6)
|
|
39
|
+
return false;
|
|
40
|
+
const normalized = new URL("http://[" + address + "]").hostname.slice(1, -1);
|
|
41
|
+
const n = v6(normalized);
|
|
42
|
+
// Conservative global-unicast subset; exclude transition, protocol, and documentation space.
|
|
43
|
+
return (n >> 125n === 1n &&
|
|
44
|
+
![
|
|
45
|
+
["2001::", 23],
|
|
46
|
+
["2001:db8::", 32],
|
|
47
|
+
["2002::", 16],
|
|
48
|
+
["3fff::", 20],
|
|
49
|
+
].some(([net, prefix]) => {
|
|
50
|
+
const shift = 128n - BigInt(prefix);
|
|
51
|
+
return n >> shift === v6(net) >> shift;
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
export function normalizeHost(host) {
|
|
55
|
+
if (!host || /[\s*/@?#\\]/.test(host))
|
|
56
|
+
throw new FetchPolicyError();
|
|
57
|
+
const value = host.startsWith("[") ? host.slice(1, -1) : host;
|
|
58
|
+
if (isIP(value))
|
|
59
|
+
return new URL(isIP(value) === 6 ? "http://[" + value + "]" : "http://" + value).hostname
|
|
60
|
+
.replace(/^\[|\]$/g, "")
|
|
61
|
+
.toLowerCase();
|
|
62
|
+
if (host.includes(":"))
|
|
63
|
+
throw new FetchPolicyError();
|
|
64
|
+
return new URL("http://" + host).hostname.toLowerCase().replace(/\.$/, "");
|
|
65
|
+
}
|
|
66
|
+
export function parseAllowedHosts(value) {
|
|
67
|
+
return value === undefined || value === "" ? [] : value.split(",").map((host) => normalizeHost(host.trim()));
|
|
68
|
+
}
|
|
69
|
+
export async function resolveDestination(urlString, options = {}) {
|
|
70
|
+
let url;
|
|
71
|
+
try {
|
|
72
|
+
url = new URL(urlString);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
throw new FetchPolicyError();
|
|
76
|
+
}
|
|
77
|
+
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || urlString.length > 8192)
|
|
78
|
+
throw new FetchPolicyError();
|
|
79
|
+
const hostname = normalizeHost(url.hostname);
|
|
80
|
+
const allowed = (options.allowedHosts ?? []).map(normalizeHost).includes(hostname);
|
|
81
|
+
if (options.restrictToAllowedHosts && !allowed)
|
|
82
|
+
throw new FetchPolicyError();
|
|
83
|
+
const version = isIP(hostname);
|
|
84
|
+
const addresses = version
|
|
85
|
+
? [{ address: hostname, family: version }]
|
|
86
|
+
: await (options.resolve ?? ((host) => lookup(host, { all: true })))(hostname);
|
|
87
|
+
if (!addresses.length ||
|
|
88
|
+
addresses.some((a) => !isIP(a.address) ||
|
|
89
|
+
isIP(a.address) !== a.family ||
|
|
90
|
+
(!isGlobalAddress(a.address) && !(allowed && options.allowPrivateHosts !== false))))
|
|
91
|
+
throw new FetchPolicyError();
|
|
92
|
+
return { url, hostname, address: addresses[0].address, family: addresses[0].family };
|
|
93
|
+
}
|
|
94
|
+
export async function assertFetchDestinationAllowed(url, options = {}) {
|
|
95
|
+
await resolveDestination(url, options);
|
|
96
|
+
}
|