effect 4.0.3 → 4.0.5
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/AGENTS.md +24 -0
- package/CLAUDE.md +24 -0
- package/ai-docs/package.json +2 -2
- package/ai-docs/src/52_graphql/10_basics.ts +117 -0
- package/ai-docs/src/52_graphql/20_testing.ts +45 -0
- package/ai-docs/src/52_graphql/30_batching.ts +118 -0
- package/ai-docs/src/52_graphql/40_aliased-batching.ts +124 -0
- package/ai-docs/src/52_graphql/50_errors-and-retries.ts +74 -0
- package/ai-docs/src/52_graphql/index.md +6 -0
- package/dist/Array.d.ts +90 -6
- package/dist/Array.d.ts.map +1 -1
- package/dist/Array.js +4 -2
- package/dist/Array.js.map +1 -1
- package/dist/Channel.d.ts +6 -1
- package/dist/Channel.d.ts.map +1 -1
- package/dist/Channel.js +17 -3
- package/dist/Channel.js.map +1 -1
- package/dist/ConfigProvider.d.ts.map +1 -1
- package/dist/ConfigProvider.js +33 -32
- package/dist/ConfigProvider.js.map +1 -1
- package/dist/Context.d.ts.map +1 -1
- package/dist/Context.js +9 -0
- package/dist/Context.js.map +1 -1
- package/dist/Duration.d.ts.map +1 -1
- package/dist/Duration.js +2 -5
- package/dist/Duration.js.map +1 -1
- package/dist/Effect.d.ts +61 -19
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +58 -39
- package/dist/Effect.js.map +1 -1
- package/dist/FileSystem.d.ts +23 -9
- package/dist/FileSystem.d.ts.map +1 -1
- package/dist/FileSystem.js.map +1 -1
- package/dist/Match.d.ts +20 -6
- package/dist/Match.d.ts.map +1 -1
- package/dist/Match.js +2 -2
- package/dist/Match.js.map +1 -1
- package/dist/Path.d.ts +37 -5
- package/dist/Path.d.ts.map +1 -1
- package/dist/Path.js +36 -5
- package/dist/Path.js.map +1 -1
- package/dist/RequestResolver.d.ts.map +1 -1
- package/dist/RequestResolver.js +4 -10
- package/dist/RequestResolver.js.map +1 -1
- package/dist/Scheduler.d.ts +9 -0
- package/dist/Scheduler.d.ts.map +1 -1
- package/dist/Scheduler.js +9 -0
- package/dist/Scheduler.js.map +1 -1
- package/dist/Schema.d.ts +15 -2
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +16 -2
- package/dist/Schema.js.map +1 -1
- package/dist/SchemaGetter.d.ts +4 -0
- package/dist/SchemaGetter.d.ts.map +1 -1
- package/dist/SchemaGetter.js +52 -33
- package/dist/SchemaGetter.js.map +1 -1
- package/dist/Sink.d.ts.map +1 -1
- package/dist/Sink.js +38 -17
- package/dist/Sink.js.map +1 -1
- package/dist/Stream.d.ts +11 -0
- package/dist/Stream.d.ts.map +1 -1
- package/dist/Stream.js +16 -1
- package/dist/Stream.js.map +1 -1
- package/dist/String.d.ts +12 -0
- package/dist/String.d.ts.map +1 -1
- package/dist/String.js +17 -4
- package/dist/String.js.map +1 -1
- package/dist/TxRef.d.ts.map +1 -1
- package/dist/TxRef.js +3 -2
- package/dist/TxRef.js.map +1 -1
- package/dist/Utils.js +8 -3
- package/dist/Utils.js.map +1 -1
- package/dist/ai/AiError.d.ts +10 -10
- package/dist/ai/AiError.d.ts.map +1 -1
- package/dist/ai/AiError.js +1 -1
- package/dist/ai/AiError.js.map +1 -1
- package/dist/ai/AnthropicStructuredOutput.js +0 -2
- package/dist/ai/AnthropicStructuredOutput.js.map +1 -1
- package/dist/ai/Chat.d.ts +2 -2
- package/dist/ai/Chat.d.ts.map +1 -1
- package/dist/ai/Decision.d.ts +70 -19
- package/dist/ai/Decision.d.ts.map +1 -1
- package/dist/ai/Decision.js +37 -3
- package/dist/ai/Decision.js.map +1 -1
- package/dist/ai/DecisionModel.js +1 -1
- package/dist/ai/DecisionModel.js.map +1 -1
- package/dist/ai/LanguageModel.d.ts +38 -7
- package/dist/ai/LanguageModel.d.ts.map +1 -1
- package/dist/ai/LanguageModel.js +70 -40
- package/dist/ai/LanguageModel.js.map +1 -1
- package/dist/ai/McpServer.d.ts +61 -52
- package/dist/ai/McpServer.d.ts.map +1 -1
- package/dist/ai/McpServer.js +134 -50
- package/dist/ai/McpServer.js.map +1 -1
- package/dist/ai/Prompt.d.ts.map +1 -1
- package/dist/ai/Prompt.js +28 -5
- package/dist/ai/Prompt.js.map +1 -1
- package/dist/ai/Response.d.ts +5 -4
- package/dist/ai/Response.d.ts.map +1 -1
- package/dist/ai/Response.js.map +1 -1
- package/dist/cli/Completions.d.ts +5 -0
- package/dist/cli/Completions.d.ts.map +1 -1
- package/dist/cli/Completions.js.map +1 -1
- package/dist/cli/Flag.d.ts +100 -0
- package/dist/cli/Flag.d.ts.map +1 -1
- package/dist/cli/Flag.js +33 -0
- package/dist/cli/Flag.js.map +1 -1
- package/dist/cli/Param.d.ts +87 -0
- package/dist/cli/Param.d.ts.map +1 -1
- package/dist/cli/Param.js +30 -0
- package/dist/cli/Param.js.map +1 -1
- package/dist/cli/internal/command.d.ts.map +1 -1
- package/dist/cli/internal/command.js +2 -1
- package/dist/cli/internal/command.js.map +1 -1
- package/dist/cli/internal/completions/bash.js +4 -3
- package/dist/cli/internal/completions/bash.js.map +1 -1
- package/dist/cli/internal/completions/descriptor.js +8 -1
- package/dist/cli/internal/completions/descriptor.js.map +1 -1
- package/dist/cli/internal/completions/fish.js +4 -4
- package/dist/cli/internal/completions/fish.js.map +1 -1
- package/dist/cli/internal/completions/powershell.js +3 -2
- package/dist/cli/internal/completions/powershell.js.map +1 -1
- package/dist/cli/internal/completions/zsh.js +7 -3
- package/dist/cli/internal/completions/zsh.js.map +1 -1
- package/dist/cli/internal/parser.js +11 -3
- package/dist/cli/internal/parser.js.map +1 -1
- package/dist/cli/internal/wizard.d.ts.map +1 -1
- package/dist/cli/internal/wizard.js +2 -1
- package/dist/cli/internal/wizard.js.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.d.ts +1 -0
- package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.js +113 -21
- package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
- package/dist/cluster/MessageStorage.d.ts.map +1 -1
- package/dist/cluster/MessageStorage.js +20 -12
- package/dist/cluster/MessageStorage.js.map +1 -1
- package/dist/cluster/Runners.d.ts.map +1 -1
- package/dist/cluster/Runners.js +54 -34
- package/dist/cluster/Runners.js.map +1 -1
- package/dist/cluster/Sharding.d.ts.map +1 -1
- package/dist/cluster/Sharding.js +6 -4
- package/dist/cluster/Sharding.js.map +1 -1
- package/dist/cluster/internal/entityManager.js +1 -1
- package/dist/cluster/internal/entityManager.js.map +1 -1
- package/dist/encoding/Sse.d.ts +6 -0
- package/dist/encoding/Sse.d.ts.map +1 -1
- package/dist/encoding/Sse.js +63 -71
- package/dist/encoding/Sse.js.map +1 -1
- package/dist/graphql/GraphQL.d.ts +349 -0
- package/dist/graphql/GraphQL.d.ts.map +1 -0
- package/dist/graphql/GraphQL.js +207 -0
- package/dist/graphql/GraphQL.js.map +1 -0
- package/dist/graphql/GraphQLClient.d.ts +562 -0
- package/dist/graphql/GraphQLClient.d.ts.map +1 -0
- package/dist/graphql/GraphQLClient.js +505 -0
- package/dist/graphql/GraphQLClient.js.map +1 -0
- package/dist/graphql/GraphQLClientError.d.ts +445 -0
- package/dist/graphql/GraphQLClientError.d.ts.map +1 -0
- package/dist/graphql/GraphQLClientError.js +479 -0
- package/dist/graphql/GraphQLClientError.js.map +1 -0
- package/dist/graphql/GraphQLGroup.d.ts +118 -0
- package/dist/graphql/GraphQLGroup.d.ts.map +1 -0
- package/dist/graphql/GraphQLGroup.js +109 -0
- package/dist/graphql/GraphQLGroup.js.map +1 -0
- package/dist/graphql/GraphQLMiddleware.d.ts +249 -0
- package/dist/graphql/GraphQLMiddleware.d.ts.map +1 -0
- package/dist/graphql/GraphQLMiddleware.js +130 -0
- package/dist/graphql/GraphQLMiddleware.js.map +1 -0
- package/dist/graphql/GraphQLProtocol.d.ts +969 -0
- package/dist/graphql/GraphQLProtocol.d.ts.map +1 -0
- package/dist/graphql/GraphQLProtocol.js +809 -0
- package/dist/graphql/GraphQLProtocol.js.map +1 -0
- package/dist/graphql/GraphQLResolver.d.ts +453 -0
- package/dist/graphql/GraphQLResolver.d.ts.map +1 -0
- package/dist/graphql/GraphQLResolver.js +582 -0
- package/dist/graphql/GraphQLResolver.js.map +1 -0
- package/dist/graphql/index.d.ts +40 -0
- package/dist/graphql/index.d.ts.map +1 -0
- package/dist/graphql/index.js +41 -0
- package/dist/graphql/index.js.map +1 -0
- package/dist/http/FetchHttpClient.d.ts +6 -3
- package/dist/http/FetchHttpClient.d.ts.map +1 -1
- package/dist/http/FetchHttpClient.js +6 -3
- package/dist/http/FetchHttpClient.js.map +1 -1
- package/dist/http/FindMyWay/internal/router.js +2 -1
- package/dist/http/FindMyWay/internal/router.js.map +1 -1
- package/dist/http/Headers.d.ts +3 -3
- package/dist/http/Headers.d.ts.map +1 -1
- package/dist/http/Headers.js +6 -5
- package/dist/http/Headers.js.map +1 -1
- package/dist/http/HttpClient.d.ts +27 -0
- package/dist/http/HttpClient.d.ts.map +1 -1
- package/dist/http/HttpClient.js +38 -11
- package/dist/http/HttpClient.js.map +1 -1
- package/dist/http/HttpClientError.d.ts.map +1 -1
- package/dist/http/HttpClientError.js +8 -6
- package/dist/http/HttpClientError.js.map +1 -1
- package/dist/http/HttpClientRequest.d.ts +147 -4
- package/dist/http/HttpClientRequest.d.ts.map +1 -1
- package/dist/http/HttpClientRequest.js +47 -1
- package/dist/http/HttpClientRequest.js.map +1 -1
- package/dist/http/HttpEffect.d.ts.map +1 -1
- package/dist/http/HttpEffect.js +14 -7
- package/dist/http/HttpEffect.js.map +1 -1
- package/dist/http/HttpMiddleware.d.ts +60 -0
- package/dist/http/HttpMiddleware.d.ts.map +1 -1
- package/dist/http/HttpMiddleware.js +93 -32
- package/dist/http/HttpMiddleware.js.map +1 -1
- package/dist/http/HttpRouter.d.ts +35 -0
- package/dist/http/HttpRouter.d.ts.map +1 -1
- package/dist/http/HttpRouter.js +87 -13
- package/dist/http/HttpRouter.js.map +1 -1
- package/dist/http/HttpServerError.d.ts.map +1 -1
- package/dist/http/HttpServerError.js +6 -4
- package/dist/http/HttpServerError.js.map +1 -1
- package/dist/http/HttpServerRequest.js +2 -2
- package/dist/http/HttpServerRequest.js.map +1 -1
- package/dist/http/HttpServerResponse.d.ts +8 -6
- package/dist/http/HttpServerResponse.d.ts.map +1 -1
- package/dist/http/HttpServerResponse.js +27 -16
- package/dist/http/HttpServerResponse.js.map +1 -1
- package/dist/http/HttpStaticServer.d.ts.map +1 -1
- package/dist/http/HttpStaticServer.js +4 -10
- package/dist/http/HttpStaticServer.js.map +1 -1
- package/dist/http/HttpTraceContext.js +1 -1
- package/dist/http/HttpTraceContext.js.map +1 -1
- package/dist/http/Multipart.d.ts.map +1 -1
- package/dist/http/Multipart.js +15 -1
- package/dist/http/Multipart.js.map +1 -1
- package/dist/http/Url.d.ts.map +1 -1
- package/dist/http/Url.js +2 -1
- package/dist/http/Url.js.map +1 -1
- package/dist/http/UrlParams.d.ts +112 -8
- package/dist/http/UrlParams.d.ts.map +1 -1
- package/dist/http/UrlParams.js +141 -14
- package/dist/http/UrlParams.js.map +1 -1
- package/dist/http/internal/compression.d.ts +1 -1
- package/dist/http/internal/compression.d.ts.map +1 -1
- package/dist/http/internal/compression.js +2 -10
- package/dist/http/internal/compression.js.map +1 -1
- package/dist/http/internal/compressionBody.d.ts +2 -0
- package/dist/http/internal/compressionBody.d.ts.map +1 -0
- package/dist/http/internal/compressionBody.js +36 -0
- package/dist/http/internal/compressionBody.js.map +1 -0
- package/dist/http/internal/decompression.d.ts +2 -0
- package/dist/http/internal/decompression.d.ts.map +1 -0
- package/dist/http/internal/decompression.js +162 -0
- package/dist/http/internal/decompression.js.map +1 -0
- package/dist/http/internal/tracing.js +14 -4
- package/dist/http/internal/tracing.js.map +1 -1
- package/dist/http/internal/urlParams.d.ts +2 -0
- package/dist/http/internal/urlParams.d.ts.map +1 -0
- package/dist/http/internal/urlParams.js +4 -0
- package/dist/http/internal/urlParams.js.map +1 -0
- package/dist/http-api/HttpApiClient.d.ts.map +1 -1
- package/dist/http-api/HttpApiClient.js +2 -1
- package/dist/http-api/HttpApiClient.js.map +1 -1
- package/dist/http-api/HttpApiScalar.d.ts +5 -0
- package/dist/http-api/HttpApiScalar.d.ts.map +1 -1
- package/dist/http-api/HttpApiScalar.js.map +1 -1
- package/dist/internal/core.js +17 -1
- package/dist/internal/core.js.map +1 -1
- package/dist/internal/dateTime.js +40 -35
- package/dist/internal/dateTime.js.map +1 -1
- package/dist/internal/effect.js +13 -6
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/graphql.d.ts +2 -0
- package/dist/internal/graphql.d.ts.map +1 -0
- package/dist/internal/graphql.js +205 -0
- package/dist/internal/graphql.js.map +1 -0
- package/dist/internal/graphqlHeaders.d.ts +4 -0
- package/dist/internal/graphqlHeaders.d.ts.map +1 -0
- package/dist/internal/graphqlHeaders.js +11 -0
- package/dist/internal/graphqlHeaders.js.map +1 -0
- package/dist/internal/request.js +20 -1
- package/dist/internal/request.js.map +1 -1
- package/dist/internal/schema/toCodeDocument.js +4 -1
- package/dist/internal/schema/toCodeDocument.js.map +1 -1
- package/dist/internal/schema/toJsonSchemaDocument.js +29 -5
- package/dist/internal/schema/toJsonSchemaDocument.js.map +1 -1
- package/dist/internal/version.js +1 -1
- package/dist/net/Host.d.ts +49 -0
- package/dist/net/Host.d.ts.map +1 -1
- package/dist/net/Host.js +55 -0
- package/dist/net/Host.js.map +1 -1
- package/dist/net/NetAddress.d.ts +8 -0
- package/dist/net/NetAddress.d.ts.map +1 -1
- package/dist/net/NetAddress.js +8 -0
- package/dist/net/NetAddress.js.map +1 -1
- package/dist/observability/Otlp.d.ts +15 -0
- package/dist/observability/Otlp.d.ts.map +1 -1
- package/dist/observability/Otlp.js +3 -0
- package/dist/observability/Otlp.js.map +1 -1
- package/dist/observability/OtlpExporter.d.ts +8 -0
- package/dist/observability/OtlpExporter.d.ts.map +1 -1
- package/dist/observability/OtlpExporter.js +10 -1
- package/dist/observability/OtlpExporter.js.map +1 -1
- package/dist/observability/OtlpLogger.d.ts +17 -0
- package/dist/observability/OtlpLogger.d.ts.map +1 -1
- package/dist/observability/OtlpLogger.js +14 -1
- package/dist/observability/OtlpLogger.js.map +1 -1
- package/dist/observability/OtlpMetrics.d.ts +17 -0
- package/dist/observability/OtlpMetrics.d.ts.map +1 -1
- package/dist/observability/OtlpMetrics.js +13 -0
- package/dist/observability/OtlpMetrics.js.map +1 -1
- package/dist/observability/OtlpTracer.d.ts +17 -0
- package/dist/observability/OtlpTracer.d.ts.map +1 -1
- package/dist/observability/OtlpTracer.js +15 -2
- package/dist/observability/OtlpTracer.js.map +1 -1
- package/dist/reactivity/AsyncResult.d.ts +6 -0
- package/dist/reactivity/AsyncResult.d.ts.map +1 -1
- package/dist/reactivity/AsyncResult.js +27 -0
- package/dist/reactivity/AsyncResult.js.map +1 -1
- package/dist/reactivity/AtomRegistry.js +3 -1
- package/dist/reactivity/AtomRegistry.js.map +1 -1
- package/dist/rpc/RpcClient.d.ts.map +1 -1
- package/dist/rpc/RpcClient.js +6 -1
- package/dist/rpc/RpcClient.js.map +1 -1
- package/dist/rpc/RpcServer.d.ts.map +1 -1
- package/dist/rpc/RpcServer.js +36 -9
- package/dist/rpc/RpcServer.js.map +1 -1
- package/dist/socket/Socket.d.ts +6 -0
- package/dist/socket/Socket.d.ts.map +1 -1
- package/dist/socket/Socket.js.map +1 -1
- package/dist/sql/SqlClient.d.ts +8 -7
- package/dist/sql/SqlClient.d.ts.map +1 -1
- package/dist/sql/SqlClient.js +8 -7
- package/dist/sql/SqlClient.js.map +1 -1
- package/dist/testing/TestClock.d.ts +16 -3
- package/dist/testing/TestClock.d.ts.map +1 -1
- package/dist/testing/TestClock.js +112 -22
- package/dist/testing/TestClock.js.map +1 -1
- package/dist/workflow/Activity.js +1 -0
- package/dist/workflow/Activity.js.map +1 -1
- package/dist/workflow/DurableDeferred.d.ts.map +1 -1
- package/dist/workflow/DurableDeferred.js +32 -3
- package/dist/workflow/DurableDeferred.js.map +1 -1
- package/dist/workflow/Workflow.d.ts +22 -0
- package/dist/workflow/Workflow.d.ts.map +1 -1
- package/dist/workflow/Workflow.js +15 -3
- package/dist/workflow/Workflow.js.map +1 -1
- package/dist/workflow/WorkflowEngine.d.ts +44 -3
- package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
- package/dist/workflow/WorkflowEngine.js +45 -22
- package/dist/workflow/WorkflowEngine.js.map +1 -1
- package/package.json +6 -3
- package/src/Array.ts +95 -6
- package/src/Channel.ts +24 -3
- package/src/ConfigProvider.ts +40 -44
- package/src/Context.ts +9 -0
- package/src/Duration.ts +4 -5
- package/src/Effect.ts +140 -53
- package/src/FileSystem.ts +23 -9
- package/src/Match.ts +65 -12
- package/src/Path.ts +52 -7
- package/src/RequestResolver.ts +4 -10
- package/src/Scheduler.ts +9 -0
- package/src/Schema.ts +25 -4
- package/src/SchemaGetter.ts +47 -35
- package/src/Sink.ts +45 -18
- package/src/Stream.ts +33 -4
- package/src/String.ts +17 -4
- package/src/TxRef.ts +4 -2
- package/src/Utils.ts +8 -5
- package/src/ai/AiError.ts +3 -1
- package/src/ai/AnthropicStructuredOutput.ts +2 -2
- package/src/ai/Chat.ts +2 -2
- package/src/ai/Decision.ts +70 -21
- package/src/ai/DecisionModel.ts +1 -1
- package/src/ai/LanguageModel.ts +141 -63
- package/src/ai/McpServer.ts +259 -145
- package/src/ai/Prompt.ts +24 -10
- package/src/ai/Response.ts +6 -3
- package/src/cli/Completions.ts +5 -0
- package/src/cli/Flag.ts +101 -0
- package/src/cli/Param.ts +96 -0
- package/src/cli/internal/command.ts +2 -1
- package/src/cli/internal/completions/bash.ts +4 -3
- package/src/cli/internal/completions/descriptor.ts +10 -1
- package/src/cli/internal/completions/fish.ts +4 -4
- package/src/cli/internal/completions/powershell.ts +5 -2
- package/src/cli/internal/completions/zsh.ts +7 -3
- package/src/cli/internal/parser.ts +12 -3
- package/src/cli/internal/wizard.ts +2 -1
- package/src/cluster/ClusterWorkflowEngine.ts +143 -36
- package/src/cluster/MessageStorage.ts +14 -3
- package/src/cluster/Runners.ts +88 -66
- package/src/cluster/Sharding.ts +12 -9
- package/src/cluster/internal/entityManager.ts +1 -1
- package/src/encoding/Sse.ts +70 -80
- package/src/graphql/GraphQL.ts +494 -0
- package/src/graphql/GraphQLClient.ts +924 -0
- package/src/graphql/GraphQLClientError.ts +542 -0
- package/src/graphql/GraphQLGroup.ts +167 -0
- package/src/graphql/GraphQLMiddleware.ts +253 -0
- package/src/graphql/GraphQLProtocol.ts +1540 -0
- package/src/graphql/GraphQLResolver.ts +1038 -0
- package/src/graphql/index.ts +48 -0
- package/src/http/FetchHttpClient.ts +6 -3
- package/src/http/FindMyWay/internal/router.ts +2 -1
- package/src/http/Headers.ts +6 -9
- package/src/http/HttpClient.ts +72 -11
- package/src/http/HttpClientError.ts +10 -6
- package/src/http/HttpClientRequest.ts +173 -7
- package/src/http/HttpEffect.ts +11 -5
- package/src/http/HttpMiddleware.ts +113 -34
- package/src/http/HttpRouter.ts +95 -13
- package/src/http/HttpServerError.ts +8 -4
- package/src/http/HttpServerRequest.ts +2 -2
- package/src/http/HttpServerResponse.ts +28 -16
- package/src/http/HttpStaticServer.ts +4 -10
- package/src/http/HttpTraceContext.ts +1 -1
- package/src/http/Multipart.ts +17 -1
- package/src/http/Url.ts +2 -1
- package/src/http/UrlParams.ts +225 -26
- package/src/http/internal/compression.ts +3 -17
- package/src/http/internal/compressionBody.ts +56 -0
- package/src/http/internal/decompression.ts +226 -0
- package/src/http/internal/tracing.ts +21 -4
- package/src/http/internal/urlParams.ts +5 -0
- package/src/http-api/HttpApiClient.ts +2 -1
- package/src/http-api/HttpApiScalar.ts +5 -0
- package/src/internal/core.ts +21 -1
- package/src/internal/dateTime.ts +13 -10
- package/src/internal/effect.ts +13 -7
- package/src/internal/graphql.ts +286 -0
- package/src/internal/graphqlHeaders.ts +11 -0
- package/src/internal/request.ts +31 -3
- package/src/internal/schema/toCodeDocument.ts +7 -1
- package/src/internal/schema/toJsonSchemaDocument.ts +34 -2
- package/src/internal/version.ts +1 -1
- package/src/net/Host.ts +72 -0
- package/src/net/NetAddress.ts +9 -0
- package/src/observability/Otlp.ts +18 -0
- package/src/observability/OtlpExporter.ts +14 -3
- package/src/observability/OtlpLogger.ts +31 -2
- package/src/observability/OtlpMetrics.ts +30 -1
- package/src/observability/OtlpTracer.ts +32 -3
- package/src/reactivity/AsyncResult.ts +31 -0
- package/src/reactivity/AtomRegistry.ts +3 -1
- package/src/rpc/RpcClient.ts +6 -1
- package/src/rpc/RpcServer.ts +55 -15
- package/src/socket/Socket.ts +6 -0
- package/src/sql/SqlClient.ts +9 -7
- package/src/testing/TestClock.ts +144 -29
- package/src/workflow/Activity.ts +1 -0
- package/src/workflow/DurableDeferred.ts +43 -5
- package/src/workflow/Workflow.ts +31 -5
- package/src/workflow/WorkflowEngine.ts +107 -25
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* @stability unstable
|
|
12
12
|
* @since 4.0.0
|
|
13
13
|
*/
|
|
14
|
+
import * as ByteSize from "../ByteSize.ts"
|
|
14
15
|
import * as Cause from "../Cause.ts"
|
|
15
16
|
import { Clock } from "../Clock.ts"
|
|
16
17
|
import * as Context from "../Context.ts"
|
|
@@ -26,6 +27,7 @@ import type { Predicate } from "../Predicate.ts"
|
|
|
26
27
|
import type { ReadonlyRecord } from "../Record.ts"
|
|
27
28
|
import { nativeTracer, ParentSpan, Tracer } from "../Tracer.ts"
|
|
28
29
|
import * as Headers from "./Headers.ts"
|
|
30
|
+
import { hasBody } from "./HttpMethod.ts"
|
|
29
31
|
import type { CompressionAlgorithm } from "./HttpPlatform.ts"
|
|
30
32
|
import { HttpPlatform } from "./HttpPlatform.ts"
|
|
31
33
|
import { causeResponseStripped, ClientAbort, HttpServerError, ResponseError } from "./HttpServerError.ts"
|
|
@@ -35,9 +37,11 @@ import * as Response from "./HttpServerResponse.ts"
|
|
|
35
37
|
import type { HttpServerResponse } from "./HttpServerResponse.ts"
|
|
36
38
|
import * as TraceContext from "./HttpTraceContext.ts"
|
|
37
39
|
import * as compressionInternal from "./internal/compression.ts"
|
|
40
|
+
import * as decompressionInternal from "./internal/decompression.ts"
|
|
38
41
|
import * as bodyInternal from "./internal/httpBody.ts"
|
|
39
42
|
import { appendPreResponseHandlerUnsafe } from "./internal/preResponseHandler.ts"
|
|
40
43
|
import * as tracing from "./internal/tracing.ts"
|
|
44
|
+
import * as UrlParams from "./UrlParams.ts"
|
|
41
45
|
|
|
42
46
|
/**
|
|
43
47
|
* Middleware that transforms an HTTP server app effect into another HTTP server app effect.
|
|
@@ -268,42 +272,37 @@ export const tracer: <E, R>(
|
|
|
268
272
|
}
|
|
269
273
|
const redactedHeaderNames = fiber.getRef(Headers.CurrentRedactedNames)
|
|
270
274
|
const headerFilter = fiber.getRef(TracerHeaderFilter)
|
|
271
|
-
fiber
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
275
|
+
// Complete the span before the request fiber exits so shutdown can flush it.
|
|
276
|
+
let response: HttpServerResponse
|
|
277
|
+
let spanExit: Exit.Exit<HttpServerResponse, unknown>
|
|
278
|
+
if (Exit.isFailure(exit)) {
|
|
279
|
+
const [failureResponse, cause] = causeResponseStripped(exit.cause)
|
|
280
|
+
response = failureResponse
|
|
281
|
+
// OpenTelemetry only treats 5xx responses as server span errors; interrupts still fail the span.
|
|
282
|
+
spanExit = Option.isSome(cause) && (response.status >= 500 || Cause.hasInterrupts(cause.value))
|
|
283
|
+
? Exit.failCause(cause.value)
|
|
284
|
+
: responseSpanExit(request, response)
|
|
285
|
+
} else {
|
|
286
|
+
response = exit.value
|
|
287
|
+
spanExit = responseSpanExit(request, response)
|
|
288
|
+
}
|
|
289
|
+
if (span.sampled) {
|
|
290
|
+
span.attribute("http.request.method", request.method)
|
|
291
|
+
const url = Request.toURL(request)
|
|
292
|
+
if (Option.isSome(url)) {
|
|
293
|
+
tracing.addUrlAttributes(span, url.value, fiber.getRef(UrlParams.CurrentRedactedNames))
|
|
294
|
+
}
|
|
295
|
+
if (request.headers["user-agent"] !== undefined) {
|
|
296
|
+
span.attribute("user_agent.original", request.headers["user-agent"])
|
|
284
297
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
if (Option.isSome(url)) {
|
|
289
|
-
if (!request.url.startsWith("/") && (url.value.username !== "" || url.value.password !== "")) {
|
|
290
|
-
url.value.username = "REDACTED"
|
|
291
|
-
url.value.password = "REDACTED"
|
|
292
|
-
}
|
|
293
|
-
tracing.addUrlAttributes(span, url.value)
|
|
294
|
-
}
|
|
295
|
-
if (request.headers["user-agent"] !== undefined) {
|
|
296
|
-
span.attribute("user_agent.original", request.headers["user-agent"])
|
|
297
|
-
}
|
|
298
|
-
tracing.addHeaderAttributes(span, "request", request.headers, headerFilter, redactedHeaderNames)
|
|
299
|
-
if (Option.isSome(request.remoteAddress)) {
|
|
300
|
-
span.attribute("client.address", request.remoteAddress.value)
|
|
301
|
-
}
|
|
302
|
-
span.attribute("http.response.status_code", response.status)
|
|
303
|
-
tracing.addHeaderAttributes(span, "response", response.headers, headerFilter, redactedHeaderNames)
|
|
298
|
+
tracing.addHeaderAttributes(span, "request", request.headers, headerFilter, redactedHeaderNames)
|
|
299
|
+
if (Option.isSome(request.remoteAddress)) {
|
|
300
|
+
span.attribute("client.address", request.remoteAddress.value)
|
|
304
301
|
}
|
|
305
|
-
span.
|
|
306
|
-
|
|
302
|
+
span.attribute("http.response.status_code", response.status)
|
|
303
|
+
tracing.addHeaderAttributes(span, "response", response.headers, headerFilter, redactedHeaderNames)
|
|
304
|
+
}
|
|
305
|
+
span.end(endTime, spanExit)
|
|
307
306
|
return undefined
|
|
308
307
|
})
|
|
309
308
|
return httpApp
|
|
@@ -627,6 +626,86 @@ export const compression = (
|
|
|
627
626
|
})
|
|
628
627
|
}
|
|
629
628
|
|
|
629
|
+
/**
|
|
630
|
+
* Middleware that decompresses request bodies sent with a `Content-Encoding`
|
|
631
|
+
* of `gzip` or `deflate`.
|
|
632
|
+
*
|
|
633
|
+
* **Details**
|
|
634
|
+
*
|
|
635
|
+
* The request service is replaced with a view whose body accessors (`stream`,
|
|
636
|
+
* `text`, `json`, `arrayBuffer`, `urlParamsBody`, `multipart`) yield the
|
|
637
|
+
* decompressed body, and whose headers no longer include `Content-Encoding`
|
|
638
|
+
* or `Content-Length`. Decompression is lazy and only happens when the body
|
|
639
|
+
* is read. Stacked codings such as `deflate, gzip` are undone in reverse
|
|
640
|
+
* order, and `identity` members are ignored.
|
|
641
|
+
*
|
|
642
|
+
* Requests whose `Content-Encoding` includes any other coding are rejected
|
|
643
|
+
* with `415 Unsupported Media Type` and `Accept-Encoding: gzip, deflate`,
|
|
644
|
+
* without running the app. Malformed compressed data fails the body read
|
|
645
|
+
* with a `RequestParseError`, or a `MultipartError` with reason `Parse` when
|
|
646
|
+
* reading multipart data.
|
|
647
|
+
*
|
|
648
|
+
* The decompressed size is limited to `maxDecompressedSize`, falling back to
|
|
649
|
+
* the `MaxBodySize` reference and then to 10 MiB. Exceeding it fails the body
|
|
650
|
+
* read with a `RequestParseError`, or a `MultipartError` with reason
|
|
651
|
+
* `BodyTooLarge` when reading multipart data. The limit applies to every body
|
|
652
|
+
* accessor, including `stream`.
|
|
653
|
+
*
|
|
654
|
+
* Decompression uses the global `DecompressionStream`. `deflate` means the
|
|
655
|
+
* zlib format (RFC 1950); raw deflate data is rejected.
|
|
656
|
+
*
|
|
657
|
+
* **Gotchas**
|
|
658
|
+
*
|
|
659
|
+
* `request.source` is still the original, compressed request.
|
|
660
|
+
* `HttpServerRequest.toWeb` returns that compressed request only when the
|
|
661
|
+
* source is a Web `Request`. On other platforms, such as Node, it builds a new
|
|
662
|
+
* `Request` from the decompressed body and the stripped headers.
|
|
663
|
+
*
|
|
664
|
+
* @stability unstable
|
|
665
|
+
* @category compression
|
|
666
|
+
* @since 4.0.0
|
|
667
|
+
*/
|
|
668
|
+
export const decompression = (
|
|
669
|
+
options?: {
|
|
670
|
+
/**
|
|
671
|
+
* Maximum number of decompressed body bytes. Defaults to the
|
|
672
|
+
* `MaxBodySize` reference, or 10 MiB when that is unset.
|
|
673
|
+
*/
|
|
674
|
+
readonly maxDecompressedSize?: ByteSize.Input | undefined
|
|
675
|
+
} | undefined
|
|
676
|
+
): <E, R>(
|
|
677
|
+
httpApp: Effect.Effect<HttpServerResponse, E, R>
|
|
678
|
+
) => Effect.Effect<HttpServerResponse, E, R | HttpServerRequest> => {
|
|
679
|
+
const maxDecompressedSize = options?.maxDecompressedSize === undefined
|
|
680
|
+
? undefined
|
|
681
|
+
: ByteSize.fromInputUnsafe(options.maxDecompressedSize)
|
|
682
|
+
return <E, R>(
|
|
683
|
+
httpApp: Effect.Effect<HttpServerResponse, E, R>
|
|
684
|
+
): Effect.Effect<HttpServerResponse, E, R | HttpServerRequest> =>
|
|
685
|
+
Effect.withFiber((fiber) => {
|
|
686
|
+
const request = Context.getUnsafe(fiber.context, HttpServerRequest)
|
|
687
|
+
const contentEncoding = request.headers["content-encoding"]
|
|
688
|
+
if (contentEncoding === undefined || !hasBody(request.method)) {
|
|
689
|
+
return httpApp
|
|
690
|
+
}
|
|
691
|
+
const codings = decompressionInternal.parseContentEncoding(contentEncoding)
|
|
692
|
+
if (codings === undefined) {
|
|
693
|
+
return Effect.succeed(Response.empty({
|
|
694
|
+
status: 415,
|
|
695
|
+
headers: { "accept-encoding": "gzip, deflate" }
|
|
696
|
+
}))
|
|
697
|
+
}
|
|
698
|
+
if (codings.length === 0) {
|
|
699
|
+
return httpApp
|
|
700
|
+
}
|
|
701
|
+
return Effect.provideService(
|
|
702
|
+
httpApp,
|
|
703
|
+
HttpServerRequest,
|
|
704
|
+
new decompressionInternal.DecompressedRequest(request, codings, maxDecompressedSize)
|
|
705
|
+
)
|
|
706
|
+
})
|
|
707
|
+
}
|
|
708
|
+
|
|
630
709
|
const withVary = (response: HttpServerResponse): HttpServerResponse => {
|
|
631
710
|
const vary = compressionInternal.varyWith(response.headers, "Accept-Encoding")
|
|
632
711
|
return Response.setHeader(response, "vary", vary)
|
package/src/http/HttpRouter.ts
CHANGED
|
@@ -24,6 +24,7 @@ import * as Scope from "../Scope.ts"
|
|
|
24
24
|
import * as Tracer from "../Tracer.ts"
|
|
25
25
|
import type * as Types from "../Types.ts"
|
|
26
26
|
import * as FindMyWay from "./FindMyWay.ts"
|
|
27
|
+
import { getClosingParenthensePosition } from "./FindMyWay/internal/router.ts"
|
|
27
28
|
import * as HttpEffect from "./HttpEffect.ts"
|
|
28
29
|
import * as HttpIncomingMessage from "./HttpIncomingMessage.ts"
|
|
29
30
|
import type * as HttpMethod from "./HttpMethod.ts"
|
|
@@ -123,7 +124,12 @@ export const HttpRouter: Context.Service<HttpRouter, HttpRouter> = Context.Servi
|
|
|
123
124
|
* @since 4.0.0
|
|
124
125
|
*/
|
|
125
126
|
export const make = Effect.gen(function*() {
|
|
126
|
-
const
|
|
127
|
+
const config = yield* RouterConfig
|
|
128
|
+
const ignoreDuplicateSlashes = config.ignoreDuplicateSlashes ?? true
|
|
129
|
+
const router = FindMyWay.make<{
|
|
130
|
+
readonly route: Route<any, never>
|
|
131
|
+
readonly prefixSegments: number | undefined
|
|
132
|
+
}>(config)
|
|
127
133
|
const middleware = new Set<middleware.Fn>()
|
|
128
134
|
|
|
129
135
|
const addAll = <const Routes extends ReadonlyArray<Route<any, any>>>(
|
|
@@ -147,19 +153,25 @@ export const make = Effect.gen(function*() {
|
|
|
147
153
|
...routes[i],
|
|
148
154
|
handler: applyMiddleware(routes[i].handler as Effect.Effect<HttpServerResponse.HttpServerResponse>)
|
|
149
155
|
})
|
|
156
|
+
const handler = {
|
|
157
|
+
route: route as Route<any, never>,
|
|
158
|
+
prefixSegments: Option.isSome(route.prefix)
|
|
159
|
+
? countSegments(route.prefix.value, ignoreDuplicateSlashes)
|
|
160
|
+
: undefined
|
|
161
|
+
}
|
|
150
162
|
if (route.method === "*") {
|
|
151
163
|
if (route.path.endsWith("/*")) {
|
|
152
|
-
router.all(route.path,
|
|
153
|
-
router.all(route.path.slice(0, -2) as any,
|
|
164
|
+
router.all(route.path, handler)
|
|
165
|
+
router.all(route.path.slice(0, -2) as any, handler)
|
|
154
166
|
} else {
|
|
155
|
-
router.all(route.path,
|
|
167
|
+
router.all(route.path, handler)
|
|
156
168
|
}
|
|
157
169
|
} else {
|
|
158
170
|
if (route.path.endsWith("/*")) {
|
|
159
|
-
router.on(route.method, route.path,
|
|
160
|
-
router.on(route.method, route.path.slice(0, -2) as any,
|
|
171
|
+
router.on(route.method, route.path, handler)
|
|
172
|
+
router.on(route.method, route.path.slice(0, -2) as any, handler)
|
|
161
173
|
} else {
|
|
162
|
-
router.on(route.method, route.path,
|
|
174
|
+
router.on(route.method, route.path, handler)
|
|
163
175
|
}
|
|
164
176
|
}
|
|
165
177
|
}
|
|
@@ -211,12 +223,12 @@ export const make = Effect.gen(function*() {
|
|
|
211
223
|
})
|
|
212
224
|
)
|
|
213
225
|
}
|
|
214
|
-
const route = result.handler
|
|
215
|
-
if (
|
|
226
|
+
const { route, prefixSegments } = result.handler
|
|
227
|
+
if (prefixSegments !== undefined) {
|
|
216
228
|
context = Context.add(
|
|
217
229
|
context,
|
|
218
230
|
HttpServerRequest.HttpServerRequest,
|
|
219
|
-
sliceRequestUrl(request,
|
|
231
|
+
sliceRequestUrl(request, prefixSegments, ignoreDuplicateSlashes)
|
|
220
232
|
)
|
|
221
233
|
}
|
|
222
234
|
context = Context.add(context, HttpServerRequest.ParsedSearchParams, result.searchParams)
|
|
@@ -251,9 +263,44 @@ export const make = Effect.gen(function*() {
|
|
|
251
263
|
})
|
|
252
264
|
})
|
|
253
265
|
|
|
254
|
-
function sliceRequestUrl(
|
|
255
|
-
|
|
256
|
-
|
|
266
|
+
function sliceRequestUrl(
|
|
267
|
+
request: HttpServerRequest.HttpServerRequest,
|
|
268
|
+
prefixSegments: number,
|
|
269
|
+
ignoreDuplicateSlashes: boolean
|
|
270
|
+
) {
|
|
271
|
+
const url = request.url
|
|
272
|
+
let index = 0
|
|
273
|
+
for (let segments = prefixSegments; segments > 0; segments--) {
|
|
274
|
+
if (ignoreDuplicateSlashes) {
|
|
275
|
+
while (url[index] === "/") index++
|
|
276
|
+
} else if (url[index] === "/") {
|
|
277
|
+
index++
|
|
278
|
+
}
|
|
279
|
+
while (index < url.length && !"/?;#".includes(url[index])) index++
|
|
280
|
+
}
|
|
281
|
+
return request.modify({ url: index < url.length ? url.slice(index) : "/" })
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function countSegments(prefix: string, ignoreDuplicateSlashes: boolean) {
|
|
285
|
+
let count = 0
|
|
286
|
+
let inParamName = false
|
|
287
|
+
for (let i = 0; i < prefix.length; i++) {
|
|
288
|
+
const char = prefix[i]
|
|
289
|
+
if (char === "/") {
|
|
290
|
+
if (!ignoreDuplicateSlashes || prefix[i - 1] !== "/") count++
|
|
291
|
+
inParamName = false
|
|
292
|
+
} else if (char === ":") {
|
|
293
|
+
if (prefix[i + 1] === ":") i++
|
|
294
|
+
else inParamName = true
|
|
295
|
+
} else if (char === "-" || char === ".") {
|
|
296
|
+
inParamName = false
|
|
297
|
+
} else if (char === "(" && inParamName) {
|
|
298
|
+
// Slashes inside parameter regexes are not segment boundaries.
|
|
299
|
+
i = getClosingParenthensePosition(prefix, i)
|
|
300
|
+
inParamName = false
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return count
|
|
257
304
|
}
|
|
258
305
|
|
|
259
306
|
/**
|
|
@@ -1410,6 +1457,41 @@ export const serve = <A, E, R, HE, HR = Request.Only<"Requires", R> | Request.On
|
|
|
1410
1457
|
* request arrives, in which case that request waits for the build to finish.
|
|
1411
1458
|
* If the build fails, every request rejects with the build error.
|
|
1412
1459
|
*
|
|
1460
|
+
* **Gotchas**
|
|
1461
|
+
*
|
|
1462
|
+
* On Cloudflare Workers, build the handler at module scope: fibers started
|
|
1463
|
+
* inside `fetch` capture that request's async context. Layer construction
|
|
1464
|
+
* must not require request-time I/O; bindings are available from
|
|
1465
|
+
* `cloudflare:workers` via its `env` export.
|
|
1466
|
+
* Prefer request-local work or a Durable Object's supported lifecycle APIs,
|
|
1467
|
+
* not indefinite background execution. For shared fibers, provide a sync
|
|
1468
|
+
* scheduler to both layers and requests as below; see `Scheduler.MixedScheduler`
|
|
1469
|
+
* for its limitations. Bound waits for shared work with request-local timeouts.
|
|
1470
|
+
*
|
|
1471
|
+
* **Example** (Opting in to the sync scheduler on Workers)
|
|
1472
|
+
*
|
|
1473
|
+
* ```ts
|
|
1474
|
+
* import { Effect, Layer, Scheduler } from "effect"
|
|
1475
|
+
* import { HttpRouter, HttpServer, HttpServerResponse } from "effect/http"
|
|
1476
|
+
*
|
|
1477
|
+
* const SyncScheduler = Layer.succeed(
|
|
1478
|
+
* Scheduler.Scheduler,
|
|
1479
|
+
* new Scheduler.MixedScheduler("sync")
|
|
1480
|
+
* )
|
|
1481
|
+
* const AppLive = HttpRouter.add(
|
|
1482
|
+
* "GET",
|
|
1483
|
+
* "/ping",
|
|
1484
|
+
* Effect.succeed(HttpServerResponse.text("pong"))
|
|
1485
|
+
* ).pipe(Layer.provide(HttpServer.layerServices))
|
|
1486
|
+
*
|
|
1487
|
+
* // Build once at module scope. The scheduler is also retained for requests.
|
|
1488
|
+
* const app = HttpRouter.toWebHandler(
|
|
1489
|
+
* AppLive.pipe(Layer.provideMerge(SyncScheduler))
|
|
1490
|
+
* )
|
|
1491
|
+
*
|
|
1492
|
+
* export default { fetch: (request: Request) => app.handler(request) }
|
|
1493
|
+
* ```
|
|
1494
|
+
*
|
|
1413
1495
|
* @stability unstable
|
|
1414
1496
|
* @category converting
|
|
1415
1497
|
* @since 4.0.0
|
|
@@ -23,6 +23,7 @@ import { hasProperty } from "../Predicate.ts"
|
|
|
23
23
|
import type * as Request from "./HttpServerRequest.ts"
|
|
24
24
|
import * as Respondable from "./HttpServerRespondable.ts"
|
|
25
25
|
import * as Response from "./HttpServerResponse.ts"
|
|
26
|
+
import * as UrlParams from "./UrlParams.ts"
|
|
26
27
|
|
|
27
28
|
const TypeId = "~effect/http/HttpServerError"
|
|
28
29
|
|
|
@@ -107,7 +108,7 @@ export class RequestParseError extends Data.TaggedError("RequestParseError")<{
|
|
|
107
108
|
}
|
|
108
109
|
|
|
109
110
|
get methodAndUrl() {
|
|
110
|
-
return
|
|
111
|
+
return formatMethodAndUrl(this.request)
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
override get message() {
|
|
@@ -139,7 +140,7 @@ export class RouteNotFound extends Data.TaggedError("RouteNotFound")<{
|
|
|
139
140
|
override readonly [ErrorReporter.ignore] = true
|
|
140
141
|
|
|
141
142
|
get methodAndUrl() {
|
|
142
|
-
return
|
|
143
|
+
return formatMethodAndUrl(this.request)
|
|
143
144
|
}
|
|
144
145
|
|
|
145
146
|
override get message() {
|
|
@@ -174,7 +175,7 @@ export class InternalError extends Data.TaggedError("InternalError")<{
|
|
|
174
175
|
}
|
|
175
176
|
|
|
176
177
|
get methodAndUrl() {
|
|
177
|
-
return
|
|
178
|
+
return formatMethodAndUrl(this.request)
|
|
178
179
|
}
|
|
179
180
|
|
|
180
181
|
override get message() {
|
|
@@ -214,7 +215,7 @@ export class ResponseError extends Data.TaggedError("ResponseError")<{
|
|
|
214
215
|
}
|
|
215
216
|
|
|
216
217
|
get methodAndUrl() {
|
|
217
|
-
return
|
|
218
|
+
return formatMethodAndUrl(this.request)
|
|
218
219
|
}
|
|
219
220
|
|
|
220
221
|
override get message() {
|
|
@@ -275,6 +276,9 @@ export class ClientAbort extends Context.Service<ClientAbort, true>()("effect/ht
|
|
|
275
276
|
)
|
|
276
277
|
}
|
|
277
278
|
|
|
279
|
+
const formatMethodAndUrl = (request: Request.HttpServerRequest) =>
|
|
280
|
+
`${request.method} ${UrlParams.redactUrl(request.url)}`
|
|
281
|
+
|
|
278
282
|
const formatRequestMessage = (reason: string, description: string | undefined, info: string) => {
|
|
279
283
|
const prefix = `${reason} (${info})`
|
|
280
284
|
return description ? `${prefix}: ${description}` : prefix
|
|
@@ -512,7 +512,7 @@ class ServerRequestImpl extends Inspectable.Class implements HttpServerRequest {
|
|
|
512
512
|
return HttpIncomingMessage.inspect(this, {
|
|
513
513
|
_id: "HttpServerRequest",
|
|
514
514
|
method: this.method,
|
|
515
|
-
url: this.originalUrl
|
|
515
|
+
url: UrlParams.redactUrl(this.originalUrl)
|
|
516
516
|
})
|
|
517
517
|
}
|
|
518
518
|
modify(
|
|
@@ -711,7 +711,7 @@ class ClientRequestImpl extends Inspectable.Class implements HttpServerRequest {
|
|
|
711
711
|
return HttpIncomingMessage.inspect(this, {
|
|
712
712
|
_id: "HttpServerRequest",
|
|
713
713
|
method: this.method,
|
|
714
|
-
url: this.originalUrl
|
|
714
|
+
url: UrlParams.redactUrl(this.originalUrl)
|
|
715
715
|
})
|
|
716
716
|
}
|
|
717
717
|
|
|
@@ -1346,23 +1346,35 @@ export const setStatus: {
|
|
|
1346
1346
|
export const omitsBody = (response: HttpServerResponse, withoutBody = false): boolean =>
|
|
1347
1347
|
withoutBody || response.status === 204 || response.status === 205 || response.status === 304
|
|
1348
1348
|
|
|
1349
|
+
const mergeHeaders = (target: globalThis.Headers, headers: globalThis.Headers): globalThis.Headers => {
|
|
1350
|
+
for (const [key, value] of headers as any) {
|
|
1351
|
+
if (key === "set-cookie") {
|
|
1352
|
+
target.append(key, value)
|
|
1353
|
+
} else {
|
|
1354
|
+
target.set(key, value)
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
return target
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1349
1360
|
/**
|
|
1350
1361
|
* Converts an `HttpServerResponse` to a Web `Response`.
|
|
1351
1362
|
*
|
|
1352
1363
|
* **Details**
|
|
1353
1364
|
*
|
|
1354
1365
|
* Cookies are appended as `Set-Cookie` headers. Stream bodies are converted using
|
|
1355
|
-
* the supplied context.
|
|
1366
|
+
* the supplied context, and are interrupted when `signal` aborts.
|
|
1356
1367
|
*
|
|
1357
1368
|
* Bodies are omitted for statuses 204, 205, and 304, or when `withoutBody` is true
|
|
1358
1369
|
* (for example, for HEAD responses). Omitted raw `ReadableStream` bodies are
|
|
1359
1370
|
* cancelled without awaiting completion, and cancellation errors are ignored.
|
|
1360
1371
|
*
|
|
1361
|
-
* A raw `Response`
|
|
1362
|
-
*
|
|
1363
|
-
*
|
|
1364
|
-
*
|
|
1365
|
-
*
|
|
1372
|
+
* A raw `Response` is returned as-is when there are no outer headers or cookies
|
|
1373
|
+
* to merge. Otherwise, they are merged into a copy without modifying the raw
|
|
1374
|
+
* response: outer headers replace native ones, and cookies are appended. When
|
|
1375
|
+
* its body is omitted, the bodyless `Response` keeps those merged
|
|
1376
|
+
* headers and uses the outer status for 204, 205 and 304, or the raw `Response`
|
|
1377
|
+
* status otherwise.
|
|
1366
1378
|
*
|
|
1367
1379
|
* @stability unstable
|
|
1368
1380
|
* @category converting
|
|
@@ -1373,6 +1385,7 @@ export const toWeb = (
|
|
|
1373
1385
|
options?: {
|
|
1374
1386
|
readonly withoutBody?: boolean | undefined
|
|
1375
1387
|
readonly context?: Context.Context<never> | undefined
|
|
1388
|
+
readonly signal?: AbortSignal | undefined
|
|
1376
1389
|
}
|
|
1377
1390
|
): Response => {
|
|
1378
1391
|
const headers = new globalThis.Headers(response.headers)
|
|
@@ -1387,15 +1400,13 @@ export const toWeb = (
|
|
|
1387
1400
|
const withoutBody = outerOmitsBody || options?.withoutBody === true
|
|
1388
1401
|
if (body._tag === "Raw" && body.body instanceof Response) {
|
|
1389
1402
|
const raw = body.body
|
|
1390
|
-
for (const [key, value] of headers as any) {
|
|
1391
|
-
if (key === "set-cookie") {
|
|
1392
|
-
raw.headers.append(key, value)
|
|
1393
|
-
} else {
|
|
1394
|
-
raw.headers.set(key, value)
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1397
1403
|
if (!withoutBody) {
|
|
1398
|
-
|
|
1404
|
+
if (headers.keys().next().done) {
|
|
1405
|
+
return raw
|
|
1406
|
+
}
|
|
1407
|
+
const copy = new Response(raw.body, raw)
|
|
1408
|
+
mergeHeaders(copy.headers, headers)
|
|
1409
|
+
return copy
|
|
1399
1410
|
}
|
|
1400
1411
|
// A bodyless outer status is what the caller chose to send; otherwise the
|
|
1401
1412
|
// body is only omitted for HEAD and the raw Response describes the resource.
|
|
@@ -1403,7 +1414,7 @@ export const toWeb = (
|
|
|
1403
1414
|
return new Response(undefined, {
|
|
1404
1415
|
status: source.status,
|
|
1405
1416
|
statusText: source.statusText as string,
|
|
1406
|
-
headers: raw.headers
|
|
1417
|
+
headers: mergeHeaders(new globalThis.Headers(raw.headers), headers)
|
|
1407
1418
|
})
|
|
1408
1419
|
}
|
|
1409
1420
|
if (withoutBody) {
|
|
@@ -1449,7 +1460,8 @@ export const toWeb = (
|
|
|
1449
1460
|
return new Response(
|
|
1450
1461
|
Stream.toReadableStreamWith(
|
|
1451
1462
|
body.stream,
|
|
1452
|
-
options?.context ?? Context.empty()
|
|
1463
|
+
options?.context ?? Context.empty(),
|
|
1464
|
+
{ signal: options?.signal }
|
|
1453
1465
|
),
|
|
1454
1466
|
{
|
|
1455
1467
|
status: response.status,
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import * as Effect from "../Effect.ts"
|
|
14
14
|
import * as FileSystem from "../FileSystem.ts"
|
|
15
15
|
import * as Layer from "../Layer.ts"
|
|
16
|
+
import * as Option from "../Option.ts"
|
|
16
17
|
import * as Path from "../Path.ts"
|
|
17
18
|
import type { PlatformError } from "../PlatformError.ts"
|
|
18
19
|
import * as HttpPlatform from "./HttpPlatform.ts"
|
|
@@ -398,16 +399,9 @@ const resolveFilePath = (path: Path.Path, root: string, url: string): string | u
|
|
|
398
399
|
if (decodedPath.includes("\u0000")) {
|
|
399
400
|
return undefined
|
|
400
401
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
}
|
|
405
|
-
const resolvedPath = path.join(root, normalizedPath)
|
|
406
|
-
const rootPrefix = root.endsWith(path.sep) ? root : `${root}${path.sep}`
|
|
407
|
-
if (resolvedPath !== root && !resolvedPath.startsWith(rootPrefix)) {
|
|
408
|
-
return undefined
|
|
409
|
-
}
|
|
410
|
-
return resolvedPath
|
|
402
|
+
// every leading separator is part of the URL, not a filesystem root
|
|
403
|
+
const relativePath = decodedPath.replace(path.sep === "\\" ? /^[/\\]+/ : /^\/+/, "")
|
|
404
|
+
return Option.getOrUndefined(path.resolveWithin(root, relativePath))
|
|
411
405
|
}
|
|
412
406
|
|
|
413
407
|
const toRouteNotFoundError = (request: HttpServerRequest.HttpServerRequest) =>
|
|
@@ -49,7 +49,7 @@ export const toHeaders = (span: Tracer.Span): Headers.Headers =>
|
|
|
49
49
|
onSome: (parent) => `-${parent.spanId}`
|
|
50
50
|
})
|
|
51
51
|
}`,
|
|
52
|
-
traceparent: `00-${span.traceId}-${span.spanId}-${span.sampled ? "01" : "00"}`
|
|
52
|
+
traceparent: `00-${span.traceId.padStart(32, "0")}-${span.spanId}-${span.sampled ? "01" : "00"}`
|
|
53
53
|
})
|
|
54
54
|
|
|
55
55
|
/**
|
package/src/http/Multipart.ts
CHANGED
|
@@ -689,6 +689,22 @@ const defaultWriteFile = (path: string, file: File) =>
|
|
|
689
689
|
(fs) => Effect.mapError(Stream.run(file.content, fs.sink(path)), toMultipartError)
|
|
690
690
|
)
|
|
691
691
|
|
|
692
|
+
const maxPersistedFileNameBytes = 128
|
|
693
|
+
const fileNameEncoder = new TextEncoder()
|
|
694
|
+
|
|
695
|
+
// Keeps the trailing 128 UTF-8 bytes without splitting code points. Empty and dot names fall back to "file".
|
|
696
|
+
const persistedFileName = (baseName: string): string => {
|
|
697
|
+
const codePoints = Array.from(baseName)
|
|
698
|
+
let fileName = ""
|
|
699
|
+
let bytes = 0
|
|
700
|
+
for (let i = codePoints.length - 1; i >= 0; i--) {
|
|
701
|
+
bytes += fileNameEncoder.encode(codePoints[i]).length
|
|
702
|
+
if (bytes > maxPersistedFileNameBytes) break
|
|
703
|
+
fileName = codePoints[i] + fileName
|
|
704
|
+
}
|
|
705
|
+
return fileName === "" || fileName === "." || fileName === ".." ? "file" : fileName
|
|
706
|
+
}
|
|
707
|
+
|
|
692
708
|
/**
|
|
693
709
|
* Runs a channel of byte chunks and collects all output into a single
|
|
694
710
|
* `Uint8Array`.
|
|
@@ -748,7 +764,7 @@ export const toPersisted = (
|
|
|
748
764
|
return Effect.void
|
|
749
765
|
}
|
|
750
766
|
const file = part
|
|
751
|
-
const fileName = path_.basename(file.name)
|
|
767
|
+
const fileName = persistedFileName(path_.basename(file.name))
|
|
752
768
|
let path = path_.join(dir, fileName)
|
|
753
769
|
while (usedPaths.has(path)) {
|
|
754
770
|
path = path_.join(dir, `${fileIndex++}-${fileName}`)
|
package/src/http/Url.ts
CHANGED
|
@@ -14,6 +14,7 @@ import * as Data from "../Data.ts"
|
|
|
14
14
|
import { dual } from "../Function.ts"
|
|
15
15
|
import * as Redacted from "../Redacted.ts"
|
|
16
16
|
import * as Result from "../Result.ts"
|
|
17
|
+
import * as internal from "./internal/urlParams.ts"
|
|
17
18
|
import * as UrlParams from "./UrlParams.ts"
|
|
18
19
|
|
|
19
20
|
/**
|
|
@@ -49,7 +50,7 @@ export const make = (
|
|
|
49
50
|
for (let i = 0; i < params.params.length; i++) {
|
|
50
51
|
const [key, value] = params.params[i]
|
|
51
52
|
if (value !== undefined) {
|
|
52
|
-
urlInstance.searchParams.append(key, value)
|
|
53
|
+
urlInstance.searchParams.append(key, internal.unwrap(value))
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
if (hash !== undefined) {
|