effect 4.0.6 → 4.0.7
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/dist/Arbitrary.d.ts +10 -2
- package/dist/Arbitrary.d.ts.map +1 -1
- package/dist/Arbitrary.js +2 -1
- package/dist/Arbitrary.js.map +1 -1
- package/dist/Channel.d.ts.map +1 -1
- package/dist/Channel.js +21 -6
- package/dist/Channel.js.map +1 -1
- package/dist/Data.d.ts +54 -235
- package/dist/Data.d.ts.map +1 -1
- package/dist/Data.js.map +1 -1
- package/dist/Effect.d.ts +1 -1
- package/dist/Effect.js +1 -1
- package/dist/Equal.d.ts.map +1 -1
- package/dist/Equal.js +8 -1
- package/dist/Equal.js.map +1 -1
- package/dist/Exit.d.ts +3 -3
- package/dist/Exit.d.ts.map +1 -1
- package/dist/Exit.js.map +1 -1
- package/dist/Formatter.d.ts.map +1 -1
- package/dist/Formatter.js +27 -13
- package/dist/Formatter.js.map +1 -1
- package/dist/Hash.d.ts.map +1 -1
- package/dist/Hash.js +4 -1
- package/dist/Hash.js.map +1 -1
- package/dist/JsonPatch.js +4 -0
- package/dist/JsonPatch.js.map +1 -1
- package/dist/JsonSchema.d.ts.map +1 -1
- package/dist/JsonSchema.js +13 -40
- package/dist/JsonSchema.js.map +1 -1
- package/dist/Metric.d.ts +3 -3
- package/dist/MutableList.d.ts +5 -2
- package/dist/MutableList.d.ts.map +1 -1
- package/dist/MutableList.js +7 -5
- package/dist/MutableList.js.map +1 -1
- package/dist/MutableRef.d.ts.map +1 -1
- package/dist/MutableRef.js +7 -0
- package/dist/MutableRef.js.map +1 -1
- package/dist/PartitionedSemaphore.d.ts +2 -1
- package/dist/PartitionedSemaphore.d.ts.map +1 -1
- package/dist/PartitionedSemaphore.js +22 -12
- package/dist/PartitionedSemaphore.js.map +1 -1
- package/dist/Pool.d.ts.map +1 -1
- package/dist/Pool.js +77 -27
- package/dist/Pool.js.map +1 -1
- package/dist/PubSub.d.ts.map +1 -1
- package/dist/PubSub.js +5 -6
- package/dist/PubSub.js.map +1 -1
- package/dist/Ref.d.ts.map +1 -1
- package/dist/Ref.js +8 -0
- package/dist/Ref.js.map +1 -1
- package/dist/Schedule.js +1 -1
- package/dist/Schedule.js.map +1 -1
- package/dist/Schema.d.ts +24 -8
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +37 -28
- package/dist/Schema.js.map +1 -1
- package/dist/SchemaAST.d.ts +4 -2
- package/dist/SchemaAST.d.ts.map +1 -1
- package/dist/SchemaAST.js +14 -17
- package/dist/SchemaAST.js.map +1 -1
- package/dist/SchemaParser.d.ts.map +1 -1
- package/dist/SchemaParser.js +48 -22
- package/dist/SchemaParser.js.map +1 -1
- package/dist/SchemaRepresentation.d.ts +19 -10
- package/dist/SchemaRepresentation.d.ts.map +1 -1
- package/dist/SchemaRepresentation.js +23 -13
- package/dist/SchemaRepresentation.js.map +1 -1
- package/dist/SchemaTransformation.d.ts +4 -1
- package/dist/SchemaTransformation.d.ts.map +1 -1
- package/dist/SchemaTransformation.js +9 -2
- package/dist/SchemaTransformation.js.map +1 -1
- package/dist/Semaphore.d.ts.map +1 -1
- package/dist/Semaphore.js +54 -35
- package/dist/Semaphore.js.map +1 -1
- package/dist/Sink.d.ts.map +1 -1
- package/dist/Sink.js +7 -2
- package/dist/Sink.js.map +1 -1
- package/dist/Stream.d.ts.map +1 -1
- package/dist/Stream.js +22 -10
- package/dist/Stream.js.map +1 -1
- package/dist/String.d.ts +3 -0
- package/dist/String.d.ts.map +1 -1
- package/dist/String.js +3 -0
- package/dist/String.js.map +1 -1
- package/dist/Tracer.d.ts +11 -1
- package/dist/Tracer.d.ts.map +1 -1
- package/dist/Tracer.js +6 -1
- package/dist/Tracer.js.map +1 -1
- package/dist/ai/LanguageModel.d.ts.map +1 -1
- package/dist/ai/LanguageModel.js +9 -0
- package/dist/ai/LanguageModel.js.map +1 -1
- package/dist/ai/McpSchema.d.ts +110 -110
- package/dist/ai/McpSchema.d.ts.map +1 -1
- package/dist/ai/McpServer.d.ts.map +1 -1
- package/dist/ai/McpServer.js +21 -15
- package/dist/ai/McpServer.js.map +1 -1
- package/dist/ai/Prompt.d.ts +52 -0
- package/dist/ai/Prompt.d.ts.map +1 -1
- package/dist/ai/Prompt.js +38 -0
- package/dist/ai/Prompt.js.map +1 -1
- package/dist/ai/Response.d.ts +16 -3
- package/dist/ai/Response.d.ts.map +1 -1
- package/dist/ai/Response.js +4 -0
- package/dist/ai/Response.js.map +1 -1
- package/dist/ai/Tool.d.ts +24 -0
- package/dist/ai/Tool.d.ts.map +1 -1
- package/dist/ai/Tool.js +5 -2
- package/dist/ai/Tool.js.map +1 -1
- package/dist/ai/Toolkit.d.ts.map +1 -1
- package/dist/ai/Toolkit.js +8 -1
- package/dist/ai/Toolkit.js.map +1 -1
- package/dist/cli/Argument.d.ts +15 -0
- package/dist/cli/Argument.d.ts.map +1 -1
- package/dist/cli/Argument.js +5 -0
- package/dist/cli/Argument.js.map +1 -1
- package/dist/cli/CliError.d.ts +78 -0
- package/dist/cli/CliError.d.ts.map +1 -1
- package/dist/cli/CliError.js +65 -3
- package/dist/cli/CliError.js.map +1 -1
- package/dist/cli/CliOutput.d.ts +155 -6
- package/dist/cli/CliOutput.d.ts.map +1 -1
- package/dist/cli/CliOutput.js +62 -6
- package/dist/cli/CliOutput.js.map +1 -1
- package/dist/cli/Command.d.ts +24 -16
- package/dist/cli/Command.d.ts.map +1 -1
- package/dist/cli/Command.js +59 -29
- package/dist/cli/Command.js.map +1 -1
- package/dist/cli/Completions.d.ts +58 -0
- package/dist/cli/Completions.d.ts.map +1 -1
- package/dist/cli/Completions.js +49 -9
- package/dist/cli/Completions.js.map +1 -1
- package/dist/cli/Flag.d.ts +15 -0
- package/dist/cli/Flag.d.ts.map +1 -1
- package/dist/cli/Flag.js +5 -0
- package/dist/cli/Flag.js.map +1 -1
- package/dist/cli/GlobalFlag.d.ts.map +1 -1
- package/dist/cli/GlobalFlag.js +15 -7
- package/dist/cli/GlobalFlag.js.map +1 -1
- package/dist/cli/Param.d.ts +9 -0
- package/dist/cli/Param.d.ts.map +1 -1
- package/dist/cli/Param.js +21 -2
- package/dist/cli/Param.js.map +1 -1
- package/dist/cli/TerminalCapabilities.d.ts +3 -2
- package/dist/cli/TerminalCapabilities.d.ts.map +1 -1
- package/dist/cli/TerminalCapabilities.js +3 -1
- package/dist/cli/TerminalCapabilities.js.map +1 -1
- package/dist/cli/internal/completions/bash.js +73 -27
- package/dist/cli/internal/completions/bash.js.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.js +45 -10
- package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
- package/dist/cluster/MessageStorage.d.ts +23 -45
- package/dist/cluster/MessageStorage.d.ts.map +1 -1
- package/dist/cluster/MessageStorage.js +6 -7
- package/dist/cluster/MessageStorage.js.map +1 -1
- package/dist/cluster/Sharding.d.ts.map +1 -1
- package/dist/cluster/Sharding.js +61 -21
- package/dist/cluster/Sharding.js.map +1 -1
- package/dist/cluster/ShardingConfig.d.ts +10 -0
- package/dist/cluster/ShardingConfig.d.ts.map +1 -1
- package/dist/cluster/ShardingConfig.js.map +1 -1
- package/dist/cluster/Snowflake.d.ts.map +1 -1
- package/dist/cluster/Snowflake.js +3 -7
- package/dist/cluster/Snowflake.js.map +1 -1
- package/dist/cluster/SqlRunnerStorage.d.ts.map +1 -1
- package/dist/cluster/SqlRunnerStorage.js +87 -39
- package/dist/cluster/SqlRunnerStorage.js.map +1 -1
- package/dist/cluster/internal/entityManager.js +54 -20
- package/dist/cluster/internal/entityManager.js.map +1 -1
- package/dist/devtools/DevToolsClient.d.ts.map +1 -1
- package/dist/devtools/DevToolsClient.js +2 -0
- package/dist/devtools/DevToolsClient.js.map +1 -1
- package/dist/encoding/Base64.js +36 -0
- package/dist/encoding/Base64.js.map +1 -1
- package/dist/encoding/Sse.d.ts.map +1 -1
- package/dist/encoding/Sse.js +3 -3
- package/dist/encoding/Sse.js.map +1 -1
- package/dist/encoding/Toml.d.ts.map +1 -1
- package/dist/encoding/Toml.js +21 -16
- package/dist/encoding/Toml.js.map +1 -1
- package/dist/eventlog/SqlEventJournal.d.ts.map +1 -1
- package/dist/eventlog/SqlEventJournal.js +47 -27
- package/dist/eventlog/SqlEventJournal.js.map +1 -1
- package/dist/eventlog/internal/conflicts.d.ts +0 -1
- package/dist/eventlog/internal/conflicts.d.ts.map +1 -1
- package/dist/eventlog/internal/conflicts.js +0 -3
- package/dist/eventlog/internal/conflicts.js.map +1 -1
- package/dist/http/Cookies.d.ts.map +1 -1
- package/dist/http/Cookies.js +10 -9
- package/dist/http/Cookies.js.map +1 -1
- package/dist/http/HttpClient.d.ts +423 -0
- package/dist/http/HttpClient.d.ts.map +1 -1
- package/dist/http/HttpClient.js +231 -7
- package/dist/http/HttpClient.js.map +1 -1
- package/dist/http/HttpClientError.d.ts +8 -1
- package/dist/http/HttpClientError.d.ts.map +1 -1
- package/dist/http/HttpClientError.js +37 -1
- package/dist/http/HttpClientError.js.map +1 -1
- package/dist/http/HttpClientRequest.d.ts.map +1 -1
- package/dist/http/HttpClientRequest.js +1 -1
- package/dist/http/HttpClientRequest.js.map +1 -1
- package/dist/http/HttpMiddleware.d.ts +1 -1
- package/dist/http/HttpMiddleware.d.ts.map +1 -1
- package/dist/http/HttpMiddleware.js +14 -16
- package/dist/http/HttpMiddleware.js.map +1 -1
- package/dist/http/HttpRouter.d.ts.map +1 -1
- package/dist/http/HttpRouter.js +2 -1
- package/dist/http/HttpRouter.js.map +1 -1
- package/dist/http/HttpServerError.js +2 -2
- package/dist/http/HttpServerError.js.map +1 -1
- package/dist/http/HttpServerRequest.d.ts +6 -1
- package/dist/http/HttpServerRequest.d.ts.map +1 -1
- package/dist/http/HttpServerRequest.js +73 -10
- package/dist/http/HttpServerRequest.js.map +1 -1
- package/dist/http/HttpStaticServer.d.ts.map +1 -1
- package/dist/http/HttpStaticServer.js +48 -21
- package/dist/http/HttpStaticServer.js.map +1 -1
- package/dist/http/MultipartParser/internal/contentType.js +3 -3
- package/dist/http/UrlParams.d.ts +3 -1
- package/dist/http/UrlParams.d.ts.map +1 -1
- package/dist/http/UrlParams.js +4 -2
- package/dist/http/UrlParams.js.map +1 -1
- package/dist/http/internal/compression.js +4 -5
- package/dist/http/internal/compression.js.map +1 -1
- package/dist/http/internal/decompression.js +3 -0
- package/dist/http/internal/decompression.js.map +1 -1
- package/dist/http/internal/httpBody.js +8 -1
- package/dist/http/internal/httpBody.js.map +1 -1
- package/dist/http/internal/urlParams.js +25 -0
- package/dist/http/internal/urlParams.js.map +1 -1
- package/dist/http-api/HttpApi.d.ts +3 -6
- package/dist/http-api/HttpApi.d.ts.map +1 -1
- package/dist/http-api/HttpApi.js +3 -6
- package/dist/http-api/HttpApi.js.map +1 -1
- package/dist/http-api/HttpApiBuilder.d.ts.map +1 -1
- package/dist/http-api/HttpApiBuilder.js +27 -11
- package/dist/http-api/HttpApiBuilder.js.map +1 -1
- package/dist/http-api/HttpApiClient.d.ts +77 -7
- package/dist/http-api/HttpApiClient.d.ts.map +1 -1
- package/dist/http-api/HttpApiClient.js +142 -44
- package/dist/http-api/HttpApiClient.js.map +1 -1
- package/dist/http-api/HttpApiEndpoint.d.ts +24 -7
- package/dist/http-api/HttpApiEndpoint.d.ts.map +1 -1
- package/dist/http-api/HttpApiEndpoint.js +109 -27
- package/dist/http-api/HttpApiEndpoint.js.map +1 -1
- package/dist/http-api/HttpApiSchema.d.ts +76 -29
- package/dist/http-api/HttpApiSchema.d.ts.map +1 -1
- package/dist/http-api/HttpApiSchema.js +70 -59
- package/dist/http-api/HttpApiSchema.js.map +1 -1
- package/dist/http-api/HttpApiTest.d.ts.map +1 -1
- package/dist/http-api/HttpApiTest.js +3 -2
- package/dist/http-api/HttpApiTest.js.map +1 -1
- package/dist/http-api/OpenApi.d.ts.map +1 -1
- package/dist/http-api/OpenApi.js +25 -16
- package/dist/http-api/OpenApi.js.map +1 -1
- package/dist/http-api/internal/toCodecHttpProperties.d.ts +2 -0
- package/dist/http-api/internal/toCodecHttpProperties.d.ts.map +1 -0
- package/dist/http-api/internal/toCodecHttpProperties.js +38 -0
- package/dist/http-api/internal/toCodecHttpProperties.js.map +1 -0
- package/dist/internal/arbitrary/runner.d.ts.map +1 -1
- package/dist/internal/arbitrary/runner.js +120 -44
- package/dist/internal/arbitrary/runner.js.map +1 -1
- package/dist/internal/core.js +2 -0
- package/dist/internal/core.js.map +1 -1
- package/dist/internal/effect.js +21 -13
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/equal.js +14 -0
- package/dist/internal/equal.js.map +1 -1
- package/dist/internal/jsonSchema.d.ts +2 -0
- package/dist/internal/jsonSchema.d.ts.map +1 -0
- package/dist/internal/jsonSchema.js +28 -0
- package/dist/internal/jsonSchema.js.map +1 -0
- package/dist/internal/matcher.js +1 -1
- package/dist/internal/matcher.js.map +1 -1
- package/dist/internal/schema/compilerRegistry.js +4 -1
- package/dist/internal/schema/compilerRegistry.js.map +1 -1
- package/dist/internal/schema/content.d.ts +2 -0
- package/dist/internal/schema/content.d.ts.map +1 -0
- package/dist/internal/schema/content.js +13 -0
- package/dist/internal/schema/content.js.map +1 -0
- package/dist/internal/schema/fromJsonSchemaDocument.js +173 -185
- package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
- package/dist/internal/schema/fromRepresentation.js +2 -1
- package/dist/internal/schema/fromRepresentation.js.map +1 -1
- package/dist/internal/schema/standardSchema.js +8 -2
- package/dist/internal/schema/standardSchema.js.map +1 -1
- package/dist/internal/schema/toCodeDocument.js +3 -3
- package/dist/internal/schema/toCodeDocument.js.map +1 -1
- package/dist/internal/schema/toCodec.js +21 -24
- package/dist/internal/schema/toCodec.js.map +1 -1
- package/dist/internal/schema/toJsonSchemaDocument.js +205 -140
- package/dist/internal/schema/toJsonSchemaDocument.js.map +1 -1
- package/dist/internal/schema/toRepresentation.js +107 -129
- package/dist/internal/schema/toRepresentation.js.map +1 -1
- package/dist/internal/sql.d.ts +2 -0
- package/dist/internal/sql.d.ts.map +1 -0
- package/dist/internal/sql.js +13 -0
- package/dist/internal/sql.js.map +1 -0
- package/dist/internal/version.js +1 -1
- package/dist/observability/OtlpProxy.d.ts +154 -0
- package/dist/observability/OtlpProxy.d.ts.map +1 -0
- package/dist/observability/OtlpProxy.js +235 -0
- package/dist/observability/OtlpProxy.js.map +1 -0
- package/dist/observability/OtlpTracer.d.ts.map +1 -1
- package/dist/observability/OtlpTracer.js +4 -0
- package/dist/observability/OtlpTracer.js.map +1 -1
- package/dist/observability/index.d.ts +5 -0
- package/dist/observability/index.d.ts.map +1 -1
- package/dist/observability/index.js +5 -0
- package/dist/observability/index.js.map +1 -1
- package/dist/persistence/CircuitBreaker.d.ts +897 -0
- package/dist/persistence/CircuitBreaker.d.ts.map +1 -0
- package/dist/persistence/CircuitBreaker.js +1165 -0
- package/dist/persistence/CircuitBreaker.js.map +1 -0
- package/dist/persistence/Redis.d.ts +78 -2
- package/dist/persistence/Redis.d.ts.map +1 -1
- package/dist/persistence/Redis.js +62 -7
- package/dist/persistence/Redis.js.map +1 -1
- package/dist/persistence/index.d.ts +5 -0
- package/dist/persistence/index.d.ts.map +1 -1
- package/dist/persistence/index.js +5 -0
- package/dist/persistence/index.js.map +1 -1
- package/dist/process/ChildProcess.d.ts +30 -4
- package/dist/process/ChildProcess.d.ts.map +1 -1
- package/dist/process/ChildProcess.js.map +1 -1
- package/dist/process/ChildProcessSpawner.d.ts +30 -0
- package/dist/process/ChildProcessSpawner.d.ts.map +1 -1
- package/dist/process/ChildProcessSpawner.js +5 -2
- package/dist/process/ChildProcessSpawner.js.map +1 -1
- package/dist/reactivity/AsyncResult.d.ts +1 -1
- package/dist/reactivity/AsyncResult.d.ts.map +1 -1
- package/dist/rpc/RpcClient.d.ts.map +1 -1
- package/dist/rpc/RpcClient.js +9 -8
- package/dist/rpc/RpcClient.js.map +1 -1
- package/dist/rpc/RpcSerialization.d.ts +14 -0
- package/dist/rpc/RpcSerialization.d.ts.map +1 -1
- package/dist/rpc/RpcSerialization.js +20 -8
- package/dist/rpc/RpcSerialization.js.map +1 -1
- package/dist/rpc/RpcServer.d.ts.map +1 -1
- package/dist/rpc/RpcServer.js +11 -1
- package/dist/rpc/RpcServer.js.map +1 -1
- package/dist/rpc/RpcTest.d.ts +1 -0
- package/dist/rpc/RpcTest.d.ts.map +1 -1
- package/dist/rpc/RpcTest.js +1 -0
- package/dist/rpc/RpcTest.js.map +1 -1
- package/dist/sql/Migrator.d.ts +2 -1
- package/dist/sql/Migrator.d.ts.map +1 -1
- package/dist/sql/Migrator.js +11 -8
- package/dist/sql/Migrator.js.map +1 -1
- package/dist/sql/SqlClient.d.ts +9 -4
- package/dist/sql/SqlClient.d.ts.map +1 -1
- package/dist/sql/SqlClient.js +8 -1
- package/dist/sql/SqlClient.js.map +1 -1
- package/dist/sql/SqlResolver.d.ts +4 -0
- package/dist/sql/SqlResolver.d.ts.map +1 -1
- package/dist/sql/SqlResolver.js +18 -4
- package/dist/sql/SqlResolver.js.map +1 -1
- package/dist/sql/Statement.d.ts +7 -0
- package/dist/sql/Statement.d.ts.map +1 -1
- package/dist/sql/Statement.js +21 -2
- package/dist/sql/Statement.js.map +1 -1
- package/dist/workflow/DurableDeferred.d.ts.map +1 -1
- package/dist/workflow/DurableDeferred.js +21 -2
- package/dist/workflow/DurableDeferred.js.map +1 -1
- package/package.json +1 -1
- package/src/Arbitrary.ts +10 -2
- package/src/Channel.ts +47 -18
- package/src/Data.ts +60 -265
- package/src/Effect.ts +1 -1
- package/src/Equal.ts +8 -1
- package/src/Exit.ts +3 -3
- package/src/Formatter.ts +28 -13
- package/src/Hash.ts +4 -1
- package/src/JsonPatch.ts +4 -0
- package/src/JsonSchema.ts +12 -40
- package/src/Metric.ts +3 -3
- package/src/MutableList.ts +7 -5
- package/src/MutableRef.ts +8 -1
- package/src/PartitionedSemaphore.ts +24 -13
- package/src/Pool.ts +109 -37
- package/src/PubSub.ts +5 -6
- package/src/Ref.ts +8 -0
- package/src/Schedule.ts +1 -1
- package/src/Schema.ts +48 -25
- package/src/SchemaAST.ts +20 -20
- package/src/SchemaParser.ts +51 -18
- package/src/SchemaRepresentation.ts +31 -34
- package/src/SchemaTransformation.ts +9 -2
- package/src/Semaphore.ts +67 -40
- package/src/Sink.ts +15 -2
- package/src/Stream.ts +33 -16
- package/src/String.ts +3 -0
- package/src/Tracer.ts +15 -1
- package/src/ai/LanguageModel.ts +9 -0
- package/src/ai/McpServer.ts +14 -13
- package/src/ai/Prompt.ts +65 -0
- package/src/ai/Response.ts +34 -9
- package/src/ai/Tool.ts +38 -2
- package/src/ai/Toolkit.ts +4 -1
- package/src/cli/Argument.ts +15 -0
- package/src/cli/CliError.ts +90 -3
- package/src/cli/CliOutput.ts +183 -6
- package/src/cli/Command.ts +53 -41
- package/src/cli/Completions.ts +51 -0
- package/src/cli/Flag.ts +15 -0
- package/src/cli/GlobalFlag.ts +6 -7
- package/src/cli/Param.ts +29 -6
- package/src/cli/TerminalCapabilities.ts +6 -3
- package/src/cli/internal/completions/bash.ts +79 -29
- package/src/cluster/ClusterWorkflowEngine.ts +46 -16
- package/src/cluster/MessageStorage.ts +19 -14
- package/src/cluster/Sharding.ts +83 -21
- package/src/cluster/ShardingConfig.ts +5 -0
- package/src/cluster/Snowflake.ts +3 -7
- package/src/cluster/SqlRunnerStorage.ts +110 -47
- package/src/cluster/internal/entityManager.ts +75 -22
- package/src/devtools/DevToolsClient.ts +2 -0
- package/src/encoding/Base64.ts +38 -0
- package/src/encoding/Sse.ts +4 -3
- package/src/encoding/Toml.ts +33 -16
- package/src/eventlog/SqlEventJournal.ts +68 -45
- package/src/eventlog/internal/conflicts.ts +0 -4
- package/src/http/Cookies.ts +10 -11
- package/src/http/HttpClient.ts +547 -7
- package/src/http/HttpClientError.ts +35 -1
- package/src/http/HttpClientRequest.ts +9 -1
- package/src/http/HttpMiddleware.ts +15 -18
- package/src/http/HttpRouter.ts +2 -1
- package/src/http/HttpServerError.ts +2 -2
- package/src/http/HttpServerRequest.ts +102 -16
- package/src/http/HttpStaticServer.ts +51 -22
- package/src/http/MultipartParser/internal/contentType.ts +3 -3
- package/src/http/UrlParams.ts +6 -1
- package/src/http/internal/compression.ts +4 -5
- package/src/http/internal/decompression.ts +6 -0
- package/src/http/internal/httpBody.ts +10 -2
- package/src/http/internal/urlParams.ts +29 -0
- package/src/http-api/HttpApi.ts +3 -6
- package/src/http-api/HttpApiBuilder.ts +45 -15
- package/src/http-api/HttpApiClient.ts +218 -72
- package/src/http-api/HttpApiEndpoint.ts +121 -30
- package/src/http-api/HttpApiSchema.ts +141 -48
- package/src/http-api/HttpApiTest.ts +3 -2
- package/src/http-api/OpenApi.ts +20 -17
- package/src/http-api/internal/toCodecHttpProperties.ts +56 -0
- package/src/internal/arbitrary/runner.ts +133 -36
- package/src/internal/core.ts +2 -0
- package/src/internal/effect.ts +24 -16
- package/src/internal/equal.ts +17 -0
- package/src/internal/jsonSchema.ts +27 -0
- package/src/internal/matcher.ts +1 -1
- package/src/internal/schema/compilerRegistry.ts +6 -1
- package/src/internal/schema/content.ts +18 -0
- package/src/internal/schema/fromJsonSchemaDocument.ts +228 -190
- package/src/internal/schema/fromRepresentation.ts +2 -1
- package/src/internal/schema/standardSchema.ts +2 -2
- package/src/internal/schema/toCodeDocument.ts +4 -4
- package/src/internal/schema/toCodec.ts +26 -22
- package/src/internal/schema/toJsonSchemaDocument.ts +189 -167
- package/src/internal/schema/toRepresentation.ts +122 -140
- package/src/internal/sql.ts +14 -0
- package/src/internal/version.ts +1 -1
- package/src/observability/OtlpProxy.ts +314 -0
- package/src/observability/OtlpTracer.ts +4 -0
- package/src/observability/index.ts +6 -0
- package/src/persistence/CircuitBreaker.ts +1678 -0
- package/src/persistence/Redis.ts +129 -8
- package/src/persistence/index.ts +6 -0
- package/src/process/ChildProcess.ts +30 -4
- package/src/process/ChildProcessSpawner.ts +41 -2
- package/src/reactivity/AsyncResult.ts +1 -1
- package/src/rpc/RpcClient.ts +13 -10
- package/src/rpc/RpcSerialization.ts +32 -9
- package/src/rpc/RpcServer.ts +16 -1
- package/src/rpc/RpcTest.ts +3 -0
- package/src/sql/Migrator.ts +12 -7
- package/src/sql/SqlClient.ts +11 -4
- package/src/sql/SqlResolver.ts +23 -9
- package/src/sql/Statement.ts +30 -2
- package/src/workflow/DurableDeferred.ts +23 -6
|
@@ -1273,7 +1273,15 @@ export const compressBody: {
|
|
|
1273
1273
|
}
|
|
1274
1274
|
return Effect.map(
|
|
1275
1275
|
compression.compressBody(self.body, algorithm, options),
|
|
1276
|
-
(body) =>
|
|
1276
|
+
(body) =>
|
|
1277
|
+
body === self.body ? self : makeWith(
|
|
1278
|
+
self.method,
|
|
1279
|
+
self.url,
|
|
1280
|
+
self.urlParams,
|
|
1281
|
+
self.hash,
|
|
1282
|
+
Headers.set(bodyInternal.updateContentLength(self.headers, body), "content-encoding", algorithm),
|
|
1283
|
+
body
|
|
1284
|
+
)
|
|
1277
1285
|
)
|
|
1278
1286
|
}
|
|
1279
1287
|
)
|
|
@@ -44,6 +44,7 @@ import * as decompressionInternal from "./internal/decompression.ts"
|
|
|
44
44
|
import * as bodyInternal from "./internal/httpBody.ts"
|
|
45
45
|
import { appendPreResponseHandlerUnsafe, CurrentRequestState } from "./internal/requestState.ts"
|
|
46
46
|
import * as tracing from "./internal/tracing.ts"
|
|
47
|
+
import * as internalUrlParams from "./internal/urlParams.ts"
|
|
47
48
|
import * as UrlParams from "./UrlParams.ts"
|
|
48
49
|
|
|
49
50
|
/**
|
|
@@ -135,19 +136,6 @@ export declare namespace HttpMiddleware {
|
|
|
135
136
|
*/
|
|
136
137
|
export const make = <M extends HttpMiddleware>(middleware: M): M => middleware
|
|
137
138
|
|
|
138
|
-
const stripSearchAndHash = (url: string): string => {
|
|
139
|
-
const queryIndex = url.indexOf("?")
|
|
140
|
-
const hashIndex = url.indexOf("#")
|
|
141
|
-
|
|
142
|
-
if (queryIndex === -1) {
|
|
143
|
-
return hashIndex === -1 ? url : url.slice(0, hashIndex)
|
|
144
|
-
}
|
|
145
|
-
if (hashIndex === -1) {
|
|
146
|
-
return url.slice(0, queryIndex)
|
|
147
|
-
}
|
|
148
|
-
return url.slice(0, Math.min(queryIndex, hashIndex))
|
|
149
|
-
}
|
|
150
|
-
|
|
151
139
|
/**
|
|
152
140
|
* Runs an effect with HTTP response logging disabled for the current server request.
|
|
153
141
|
*
|
|
@@ -232,7 +220,7 @@ export const logger: <E, R>(
|
|
|
232
220
|
Effect.withFiber((fiber) => {
|
|
233
221
|
const request = Context.getUnsafe(fiber.context, HttpServerRequest)
|
|
234
222
|
const state = Context.getOrUndefined(fiber.context, CurrentRequestState)
|
|
235
|
-
const path = stripSearchAndHash(request.url)
|
|
223
|
+
const path = internalUrlParams.stripSearchAndHash(request.url)
|
|
236
224
|
return Effect.withLogSpan(
|
|
237
225
|
Effect.flatMap(Effect.exit(httpApp), (exit) => {
|
|
238
226
|
if (state?.loggerDisabled) {
|
|
@@ -278,12 +266,19 @@ export const isTracerDisabledUnsafe = (
|
|
|
278
266
|
|
|
279
267
|
// OpenTelemetry requires failed server spans for 5xx responses.
|
|
280
268
|
const responseSpanExit = (
|
|
269
|
+
fiber: Fiber.Fiber<unknown, unknown>,
|
|
281
270
|
request: HttpServerRequest,
|
|
282
271
|
response: HttpServerResponse
|
|
283
272
|
): Exit.Exit<HttpServerResponse, HttpServerError> => {
|
|
284
273
|
if (!(response.status >= 500 && response.status < 600)) {
|
|
285
274
|
return Exit.succeed(response)
|
|
286
275
|
}
|
|
276
|
+
// The message is path-only, but exporters can still read `error.request.url`
|
|
277
|
+
// after the request-scoped redacted names are gone.
|
|
278
|
+
const url = UrlParams.redactUrl(request.url, fiber.getRef(UrlParams.CurrentRedactedNames))
|
|
279
|
+
if (url !== request.url) {
|
|
280
|
+
request = request.modify({ url })
|
|
281
|
+
}
|
|
287
282
|
const stackTraceLimit = getStackTraceLimit()
|
|
288
283
|
setStackTraceLimit(0)
|
|
289
284
|
try {
|
|
@@ -319,7 +314,7 @@ export const tracer: <E, R>(
|
|
|
319
314
|
fiber.setContext(prevServices)
|
|
320
315
|
const endTime = fiber.getRef(Clock).currentTimeNanosUnsafe()
|
|
321
316
|
if (Exit.isSuccess(exit) && (!span.sampled || fiber.getRef(Tracer) === nativeTracer)) {
|
|
322
|
-
span.end(endTime, responseSpanExit(request, exit.value))
|
|
317
|
+
span.end(endTime, responseSpanExit(fiber, request, exit.value))
|
|
323
318
|
return undefined
|
|
324
319
|
}
|
|
325
320
|
const redactedHeaderNames = fiber.getRef(Headers.CurrentRedactedNames)
|
|
@@ -333,10 +328,10 @@ export const tracer: <E, R>(
|
|
|
333
328
|
// OpenTelemetry only treats 5xx responses as server span errors; interrupts still fail the span.
|
|
334
329
|
spanExit = Option.isSome(cause) && (response.status >= 500 || Cause.hasInterrupts(cause.value))
|
|
335
330
|
? Exit.failCause(cause.value)
|
|
336
|
-
: responseSpanExit(request, response)
|
|
331
|
+
: responseSpanExit(fiber, request, response)
|
|
337
332
|
} else {
|
|
338
333
|
response = exit.value
|
|
339
|
-
spanExit = responseSpanExit(request, response)
|
|
334
|
+
spanExit = responseSpanExit(fiber, request, response)
|
|
340
335
|
}
|
|
341
336
|
if (span.sampled) {
|
|
342
337
|
span.attribute("http.request.method", request.method)
|
|
@@ -434,7 +429,9 @@ export interface TrustedProxyOptions {
|
|
|
434
429
|
* @category proxying
|
|
435
430
|
* @since 4.0.0
|
|
436
431
|
*/
|
|
437
|
-
export const xForwardedHeaders = (options: TrustedProxyOptions):
|
|
432
|
+
export const xForwardedHeaders = (options: TrustedProxyOptions): <E, R>(
|
|
433
|
+
httpApp: Effect.Effect<HttpServerResponse, E, HttpServerRequest | R>
|
|
434
|
+
) => Effect.Effect<HttpServerResponse, E, HttpServerRequest | R> => {
|
|
438
435
|
const { trustedProxies } = options
|
|
439
436
|
const isTrusted: Predicate<NetAddress.IpAddress> = typeof trustedProxies === "function"
|
|
440
437
|
? trustedProxies
|
package/src/http/HttpRouter.ts
CHANGED
|
@@ -284,7 +284,8 @@ function sliceRequestUrl(
|
|
|
284
284
|
}
|
|
285
285
|
while (index < url.length && !"/?;#".includes(url[index])) index++
|
|
286
286
|
}
|
|
287
|
-
|
|
287
|
+
const rest = url.slice(index)
|
|
288
|
+
return request.modify({ url: rest.startsWith("/") ? rest : "/" + rest })
|
|
288
289
|
}
|
|
289
290
|
|
|
290
291
|
function countSegments(prefix: string, ignoreDuplicateSlashes: boolean) {
|
|
@@ -23,7 +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
|
|
26
|
+
import * as internalUrlParams from "./internal/urlParams.ts"
|
|
27
27
|
|
|
28
28
|
const TypeId = "~effect/http/HttpServerError"
|
|
29
29
|
|
|
@@ -280,7 +280,7 @@ export class ClientAbort extends Context.Service<ClientAbort, true>()("effect/ht
|
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
const formatMethodAndUrl = (request: Request.HttpServerRequest) =>
|
|
283
|
-
`${request.method} ${
|
|
283
|
+
`${request.method} ${internalUrlParams.toPath(request.url)}`
|
|
284
284
|
|
|
285
285
|
const formatRequestMessage = (reason: string, description: string | undefined, info: string) => {
|
|
286
286
|
const prefix = `${reason} (${info})`
|
|
@@ -77,7 +77,9 @@ export const TypeId = "~effect/http/HttpServerRequest"
|
|
|
77
77
|
* creating adjusted request views. `upgrade` completes a WebSocket handshake
|
|
78
78
|
* for `Upgrade: websocket`. Platforms that can hand over the connection, such
|
|
79
79
|
* as Node, answer other protocols with `101 Switching Protocols` and expose
|
|
80
|
-
* the raw connection.
|
|
80
|
+
* the raw connection. `upgradeWith` does the same and adds custom headers to
|
|
81
|
+
* the `101` response; `upgrade` is `upgradeWith({})`. WebSocket upgrades fail
|
|
82
|
+
* when custom headers are given.
|
|
81
83
|
*
|
|
82
84
|
* @stability unstable
|
|
83
85
|
* @category models
|
|
@@ -99,6 +101,9 @@ export interface HttpServerRequest extends HttpIncomingMessage.HttpIncomingMessa
|
|
|
99
101
|
readonly multipartStream: Stream.Stream<Multipart.Part, Multipart.MultipartError>
|
|
100
102
|
|
|
101
103
|
readonly upgrade: Effect.Effect<Socket.Socket, HttpServerError>
|
|
104
|
+
readonly upgradeWith: (options: {
|
|
105
|
+
readonly headers?: Headers.Input | undefined
|
|
106
|
+
}) => Effect.Effect<Socket.Socket, HttpServerError>
|
|
102
107
|
|
|
103
108
|
/**
|
|
104
109
|
* Address of the directly connected peer. Trusted proxy middleware replaces
|
|
@@ -610,18 +615,23 @@ class ServerRequestImpl extends Inspectable.Class implements HttpServerRequest {
|
|
|
610
615
|
if (this.textEffect) {
|
|
611
616
|
return this.textEffect
|
|
612
617
|
}
|
|
613
|
-
this.textEffect = Effect.
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
618
|
+
this.textEffect = Effect.withFiber((fiber) =>
|
|
619
|
+
fiber.getRef(HttpIncomingMessage.MaxBodySize) === undefined
|
|
620
|
+
? Effect.tryPromise({
|
|
621
|
+
try: () => this.source.text(),
|
|
622
|
+
catch: (cause) =>
|
|
623
|
+
new HttpServerError({
|
|
624
|
+
reason: new RequestParseError({
|
|
625
|
+
request: this,
|
|
626
|
+
cause
|
|
627
|
+
})
|
|
621
628
|
})
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
)
|
|
629
|
+
})
|
|
630
|
+
: Effect.map(this.arrayBuffer, (buffer) => textDecoder.decode(buffer))
|
|
631
|
+
).pipe(
|
|
632
|
+
Effect.cached,
|
|
633
|
+
Effect.runSync
|
|
634
|
+
)
|
|
625
635
|
return this.textEffect
|
|
626
636
|
}
|
|
627
637
|
|
|
@@ -686,22 +696,36 @@ class ServerRequestImpl extends Inspectable.Class implements HttpServerRequest {
|
|
|
686
696
|
if (this.arrayBufferEffect) {
|
|
687
697
|
return this.arrayBufferEffect
|
|
688
698
|
}
|
|
689
|
-
this.arrayBufferEffect = Effect.
|
|
690
|
-
|
|
691
|
-
|
|
699
|
+
this.arrayBufferEffect = Effect.withFiber((fiber) => {
|
|
700
|
+
const maxBodySize = fiber.getRef(HttpIncomingMessage.MaxBodySize)
|
|
701
|
+
return Effect.tryPromise({
|
|
702
|
+
try: (signal) =>
|
|
703
|
+
maxBodySize === undefined
|
|
704
|
+
? this.source.arrayBuffer()
|
|
705
|
+
: readArrayBufferLimited(this.source, Number(maxBodySize), signal),
|
|
692
706
|
catch: (cause) =>
|
|
693
707
|
new HttpServerError({
|
|
694
708
|
reason: new RequestParseError({
|
|
695
709
|
request: this,
|
|
710
|
+
reason: cause instanceof BodyTooLargeError ? "BodyTooLarge" : "Parse",
|
|
696
711
|
cause
|
|
697
712
|
})
|
|
698
713
|
})
|
|
699
714
|
})
|
|
700
|
-
)
|
|
715
|
+
}).pipe(
|
|
716
|
+
Effect.cached,
|
|
717
|
+
Effect.runSync
|
|
718
|
+
)
|
|
701
719
|
return this.arrayBufferEffect
|
|
702
720
|
}
|
|
703
721
|
|
|
704
722
|
get upgrade(): Effect.Effect<Socket.Socket, HttpServerError> {
|
|
723
|
+
return this.upgradeWith({})
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
upgradeWith(
|
|
727
|
+
_options: { readonly headers?: Headers.Input | undefined }
|
|
728
|
+
): Effect.Effect<Socket.Socket, HttpServerError> {
|
|
705
729
|
return Effect.fail(
|
|
706
730
|
new HttpServerError({
|
|
707
731
|
reason: new RequestParseError({
|
|
@@ -916,6 +940,12 @@ class ClientRequestImpl extends Inspectable.Class implements HttpServerRequest {
|
|
|
916
940
|
}
|
|
917
941
|
|
|
918
942
|
get upgrade(): Effect.Effect<Socket.Socket, HttpServerError> {
|
|
943
|
+
return this.upgradeWith({})
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
upgradeWith(
|
|
947
|
+
_options: { readonly headers?: Headers.Input | undefined }
|
|
948
|
+
): Effect.Effect<Socket.Socket, HttpServerError> {
|
|
919
949
|
return Effect.fail(requestParseError(this, "Not an upgradeable ServerRequest"))
|
|
920
950
|
}
|
|
921
951
|
}
|
|
@@ -1080,6 +1110,62 @@ const isBodyInit = (u: unknown): u is BodyInit =>
|
|
|
1080
1110
|
|
|
1081
1111
|
const textDecoder = new TextDecoder()
|
|
1082
1112
|
|
|
1113
|
+
class BodyTooLargeError extends Error {
|
|
1114
|
+
constructor(maxBytes: number) {
|
|
1115
|
+
super(`Request body exceeds ${maxBytes} bytes`)
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
const readArrayBufferLimited = async (
|
|
1120
|
+
source: Request,
|
|
1121
|
+
maxBytes: number,
|
|
1122
|
+
signal: AbortSignal
|
|
1123
|
+
): Promise<ArrayBuffer> => {
|
|
1124
|
+
const header = source.headers.get("content-length")
|
|
1125
|
+
const contentLength = header !== null && /^\d+$/.test(header) ? Number(header) : undefined
|
|
1126
|
+
if (contentLength !== undefined && contentLength > maxBytes) {
|
|
1127
|
+
throw new BodyTooLargeError(maxBytes)
|
|
1128
|
+
}
|
|
1129
|
+
if (source.body === null) {
|
|
1130
|
+
return new ArrayBuffer(0)
|
|
1131
|
+
}
|
|
1132
|
+
// A constructed request can understate its content-length, so bytes are
|
|
1133
|
+
// counted on every runtime. Cancellation is not awaited, as the source's
|
|
1134
|
+
// cleanup may never settle.
|
|
1135
|
+
const limit = contentLength ?? maxBytes
|
|
1136
|
+
const reader = source.body.getReader()
|
|
1137
|
+
const cancel = () => {
|
|
1138
|
+
reader.cancel().catch(() => {})
|
|
1139
|
+
}
|
|
1140
|
+
signal.addEventListener("abort", cancel, { once: true })
|
|
1141
|
+
const chunks: Array<Uint8Array> = []
|
|
1142
|
+
let bytes = 0
|
|
1143
|
+
try {
|
|
1144
|
+
while (true) {
|
|
1145
|
+
const { done, value } = await reader.read()
|
|
1146
|
+
if (done) break
|
|
1147
|
+
bytes += value.byteLength
|
|
1148
|
+
if (bytes > limit) {
|
|
1149
|
+
cancel()
|
|
1150
|
+
throw bytes > maxBytes
|
|
1151
|
+
? new BodyTooLargeError(maxBytes)
|
|
1152
|
+
: new Error(`Request body is longer than its content-length of ${contentLength}`)
|
|
1153
|
+
}
|
|
1154
|
+
chunks.push(value)
|
|
1155
|
+
}
|
|
1156
|
+
} finally {
|
|
1157
|
+
signal.removeEventListener("abort", cancel)
|
|
1158
|
+
reader.releaseLock()
|
|
1159
|
+
}
|
|
1160
|
+
const buffer = new Uint8Array(bytes)
|
|
1161
|
+
let offset = 0
|
|
1162
|
+
for (const chunk of chunks) {
|
|
1163
|
+
buffer.set(chunk, offset)
|
|
1164
|
+
offset += chunk.byteLength
|
|
1165
|
+
}
|
|
1166
|
+
return buffer.buffer
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1083
1169
|
/**
|
|
1084
1170
|
* Attempts to construct an absolute `URL` for a server request safely.
|
|
1085
1171
|
*
|
|
@@ -121,7 +121,9 @@ export const make: (options: {
|
|
|
121
121
|
) => Effect.Effect<HttpServerResponse.HttpServerResponse, HttpServerError.HttpServerError> = Effect.fnUntraced(
|
|
122
122
|
function*(request, filePath, fileSize) {
|
|
123
123
|
const rangeHeader = request.method === "GET" ? request.headers["range"] : undefined
|
|
124
|
-
const shouldEvaluateConditionals = request.headers["if-
|
|
124
|
+
const shouldEvaluateConditionals = request.headers["if-match"] !== undefined ||
|
|
125
|
+
request.headers["if-unmodified-since"] !== undefined ||
|
|
126
|
+
request.headers["if-none-match"] !== undefined ||
|
|
125
127
|
request.headers["if-modified-since"] !== undefined
|
|
126
128
|
|
|
127
129
|
let fullResponse: HttpServerResponse.HttpServerResponse | undefined
|
|
@@ -446,6 +448,22 @@ const stripWeakEtagPrefix = (value: string): string => {
|
|
|
446
448
|
return /^w\//i.test(trimmed) ? trimmed.slice(2) : trimmed;
|
|
447
449
|
}
|
|
448
450
|
|
|
451
|
+
// If-Match uses strong comparison (RFC 9110 §13.1.1), so weak tags never
|
|
452
|
+
// match. Tags may contain commas, so the list is validated whole rather than
|
|
453
|
+
// split, and a malformed list matches nothing.
|
|
454
|
+
const entityTagList = /^[\s,]*(?:(?:W\/)?"[^"]*"\s*(?:,[\s,]*|$))*$/
|
|
455
|
+
const entityTag = /(?:W\/)?"[^"]*"/g
|
|
456
|
+
|
|
457
|
+
const matchesIfMatch = (ifMatch: string, etag: string | undefined): boolean => {
|
|
458
|
+
if (ifMatch.trim() === "*") {
|
|
459
|
+
return true
|
|
460
|
+
}
|
|
461
|
+
if (etag === undefined || !etag.startsWith("\"") || !entityTagList.test(ifMatch)) {
|
|
462
|
+
return false
|
|
463
|
+
}
|
|
464
|
+
return ifMatch.match(entityTag)?.includes(etag) ?? false
|
|
465
|
+
}
|
|
466
|
+
|
|
449
467
|
const matchesIfNoneMatch = (ifNoneMatch: string, etag: string | undefined): boolean => {
|
|
450
468
|
const normalizedEtag = etag === undefined ? undefined : stripWeakEtagPrefix(etag)
|
|
451
469
|
for (const candidate of ifNoneMatch.split(",")) {
|
|
@@ -463,18 +481,19 @@ const matchesIfNoneMatch = (ifNoneMatch: string, etag: string | undefined): bool
|
|
|
463
481
|
return false
|
|
464
482
|
}
|
|
465
483
|
|
|
466
|
-
// An invalid date on either side disables the precondition (RFC 9110 §13.1.3).
|
|
467
|
-
const
|
|
484
|
+
// An invalid date on either side disables the precondition (RFC 9110 §13.1.3–4).
|
|
485
|
+
const isModifiedSince = (since: string, lastModified: string | undefined): boolean | undefined => {
|
|
468
486
|
if (lastModified === undefined) {
|
|
469
|
-
return
|
|
487
|
+
return undefined
|
|
470
488
|
}
|
|
471
|
-
const
|
|
472
|
-
if (Result.isFailure(
|
|
473
|
-
return
|
|
489
|
+
const sinceDate = Headers.parseHttpDate(since)
|
|
490
|
+
if (Result.isFailure(sinceDate)) {
|
|
491
|
+
return undefined
|
|
474
492
|
}
|
|
475
493
|
const lastModifiedDate = Headers.parseHttpDate(lastModified)
|
|
476
|
-
return Result.isSuccess(lastModifiedDate)
|
|
477
|
-
DateTime.toEpochMillis(lastModifiedDate.success)
|
|
494
|
+
return Result.isSuccess(lastModifiedDate)
|
|
495
|
+
? DateTime.toEpochMillis(lastModifiedDate.success) > DateTime.toEpochMillis(sinceDate.success)
|
|
496
|
+
: undefined
|
|
478
497
|
}
|
|
479
498
|
|
|
480
499
|
// Only a strong entity-tag can match (RFC 9110 §13.1.5). Weak tags start
|
|
@@ -485,21 +504,18 @@ const matchesIfRange = (ifRange: string, etag: string | undefined): boolean => {
|
|
|
485
504
|
return value.startsWith("\"") && value === etag
|
|
486
505
|
}
|
|
487
506
|
|
|
507
|
+
// Headers a 304 must repeat from the 200 response (RFC 9110 §15.4.5), plus Last-Modified for revalidation.
|
|
508
|
+
const notModifiedHeaders = ["cache-control", "content-location", "date", "etag", "expires", "last-modified", "vary"]
|
|
509
|
+
|
|
488
510
|
const notModifiedResponse = (
|
|
489
511
|
response: HttpServerResponse.HttpServerResponse
|
|
490
512
|
): HttpServerResponse.HttpServerResponse => {
|
|
491
513
|
const headers: Record<string, string> = {}
|
|
492
|
-
const
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
if (cacheControl !== undefined) {
|
|
498
|
-
headers["Cache-Control"] = cacheControl
|
|
499
|
-
}
|
|
500
|
-
const lastModified = response.headers["last-modified"]
|
|
501
|
-
if (lastModified !== undefined) {
|
|
502
|
-
headers["Last-Modified"] = lastModified
|
|
514
|
+
for (const name of notModifiedHeaders) {
|
|
515
|
+
const value = response.headers[name]
|
|
516
|
+
if (value !== undefined) {
|
|
517
|
+
headers[name] = value
|
|
518
|
+
}
|
|
503
519
|
}
|
|
504
520
|
return HttpServerResponse.empty({
|
|
505
521
|
status: 304,
|
|
@@ -511,12 +527,25 @@ const evaluateConditionalRequest = (
|
|
|
511
527
|
request: HttpServerRequest.HttpServerRequest,
|
|
512
528
|
response: HttpServerResponse.HttpServerResponse
|
|
513
529
|
): HttpServerResponse.HttpServerResponse | undefined => {
|
|
530
|
+
const etag = response.headers["etag"]
|
|
531
|
+
const lastModified = response.headers["last-modified"]
|
|
532
|
+
const ifMatch = request.headers["if-match"]
|
|
533
|
+
if (ifMatch !== undefined) {
|
|
534
|
+
if (!matchesIfMatch(ifMatch, etag)) {
|
|
535
|
+
return HttpServerResponse.empty({ status: 412 })
|
|
536
|
+
}
|
|
537
|
+
} else {
|
|
538
|
+
const ifUnmodifiedSince = request.headers["if-unmodified-since"]
|
|
539
|
+
if (ifUnmodifiedSince !== undefined && isModifiedSince(ifUnmodifiedSince, lastModified) === true) {
|
|
540
|
+
return HttpServerResponse.empty({ status: 412 })
|
|
541
|
+
}
|
|
542
|
+
}
|
|
514
543
|
const ifNoneMatch = request.headers["if-none-match"]
|
|
515
544
|
if (ifNoneMatch !== undefined) {
|
|
516
|
-
return matchesIfNoneMatch(ifNoneMatch,
|
|
545
|
+
return matchesIfNoneMatch(ifNoneMatch, etag) ? notModifiedResponse(response) : undefined
|
|
517
546
|
}
|
|
518
547
|
const ifModifiedSince = request.headers["if-modified-since"]
|
|
519
|
-
if (ifModifiedSince !== undefined &&
|
|
548
|
+
if (ifModifiedSince !== undefined && isModifiedSince(ifModifiedSince, lastModified) === false) {
|
|
520
549
|
return notModifiedResponse(response)
|
|
521
550
|
}
|
|
522
551
|
return undefined
|
|
@@ -16,14 +16,14 @@
|
|
|
16
16
|
* quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
|
17
17
|
*/
|
|
18
18
|
const paramRE =
|
|
19
|
-
/; *([!#$%&'*+.^\w`|~-]+)=("(?:[\
|
|
19
|
+
/; *([!#$%&'*+.^\w`|~-]+)=("(?:[\t\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u{10ffff}]|\\[\t\u0020-\u{10ffff}])*"|[!#$%&'*+.^\w`|~-]+) */gu
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* RegExp to match *( ";" disposition-parm ) in RFC 6266 sec 4.1, which allows
|
|
23
23
|
* optional whitespace around separators
|
|
24
24
|
*/
|
|
25
25
|
const dispositionParamRE =
|
|
26
|
-
/;[ \t]*([!#$%&'*+.^\w`|~-]+)[ \t]*=[ \t]*("(?:[\
|
|
26
|
+
/;[ \t]*([!#$%&'*+.^\w`|~-]+)[ \t]*=[ \t]*("(?:[\t\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u{10ffff}]|\\[\t\u0020-\u{10ffff}])*"|[!#$%&'*+.^\w`|~-]+)[ \t]*/gu
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* RegExp to match quoted-pair in RFC 7230 sec 3.2.6
|
|
@@ -31,7 +31,7 @@ const dispositionParamRE =
|
|
|
31
31
|
* quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
|
32
32
|
* obs-text = %x80-FF
|
|
33
33
|
*/
|
|
34
|
-
const quotedPairRE = /\\([\
|
|
34
|
+
const quotedPairRE = /\\([\t\u0020-\u{10ffff}])/gu
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* RegExp to match type in RFC 7231 sec 3.1.1.1
|
package/src/http/UrlParams.ts
CHANGED
|
@@ -870,7 +870,9 @@ const currentRedactedNames = (): ReadonlyArray<string | RegExp> =>
|
|
|
870
870
|
*
|
|
871
871
|
* **Details**
|
|
872
872
|
*
|
|
873
|
-
* Defaults
|
|
873
|
+
* Defaults match the OpenTelemetry `url.full` list: `X-Amz-Signature`,
|
|
874
|
+
* `X-Amz-Credential`, `X-Amz-Security-Token`, `AWSAccessKeyId`, `Signature`,
|
|
875
|
+
* `sig` and `X-Goog-Signature`.
|
|
874
876
|
* A custom list replaces the defaults. Matching uses `isRedactedName`.
|
|
875
877
|
* Redaction leaves request URLs and parameter values unchanged. `Redacted`
|
|
876
878
|
* values are redacted regardless of this list.
|
|
@@ -883,6 +885,9 @@ export const CurrentRedactedNames = Context.Reference<
|
|
|
883
885
|
ReadonlyArray<string | RegExp>
|
|
884
886
|
>("effect/http/UrlParams/CurrentRedactedNames", {
|
|
885
887
|
defaultValue: () => [
|
|
888
|
+
"X-Amz-Signature",
|
|
889
|
+
"X-Amz-Credential",
|
|
890
|
+
"X-Amz-Security-Token",
|
|
886
891
|
"AWSAccessKeyId",
|
|
887
892
|
"Signature",
|
|
888
893
|
"sig",
|
|
@@ -155,13 +155,12 @@ const acceptMember = /^([a-z0-9!#$%&'*+.^_`|~-]+)(?:;q=(0(?:\.[0-9]{0,3})?|1(?:\
|
|
|
155
155
|
* @internal
|
|
156
156
|
*/
|
|
157
157
|
export const parseAcceptEncoding = (header: string): ReadonlyMap<string, number> | undefined => {
|
|
158
|
-
const trimmed = header.trim()
|
|
159
|
-
if (trimmed === "") {
|
|
160
|
-
return undefined
|
|
161
|
-
}
|
|
162
158
|
const accepted = new Map<string, number>()
|
|
163
|
-
for (const part of
|
|
159
|
+
for (const part of header.split(",")) {
|
|
164
160
|
const member = part.trim().toLowerCase().replace(/[ \t]*;[ \t]*/g, ";")
|
|
161
|
+
if (member === "") {
|
|
162
|
+
continue
|
|
163
|
+
}
|
|
165
164
|
const match = acceptMember.exec(member)
|
|
166
165
|
if (match === null) {
|
|
167
166
|
return undefined
|
|
@@ -124,6 +124,12 @@ export class DecompressedRequest extends Inspectable.Class implements HttpServer
|
|
|
124
124
|
return this.inner.upgrade
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
upgradeWith(
|
|
128
|
+
options: { readonly headers?: Headers.Input | undefined }
|
|
129
|
+
): Effect.Effect<Socket.Socket, HttpServerError> {
|
|
130
|
+
return this.inner.upgradeWith(options)
|
|
131
|
+
}
|
|
132
|
+
|
|
127
133
|
// Platform accessors such as `NodeHttpServerRequest.toServerResponse` read
|
|
128
134
|
// the response handle from the request.
|
|
129
135
|
get response(): unknown {
|
|
@@ -11,9 +11,17 @@ export const updateHeaders = (headers: Headers.Headers, body: HttpBody.HttpBody)
|
|
|
11
11
|
headers = body.contentType === undefined
|
|
12
12
|
? Headers.remove(headers, "content-type")
|
|
13
13
|
: Headers.set(headers, "content-type", body.contentType)
|
|
14
|
-
return body
|
|
14
|
+
return updateContentLength(headers, body)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export const updateContentLength = (headers: Headers.Headers, body: HttpBody.HttpBody): Headers.Headers => {
|
|
21
|
+
const contentLength = body._tag === "Empty" || body._tag === "FormData" ? undefined : body.contentLength
|
|
22
|
+
return contentLength === undefined
|
|
15
23
|
? Headers.remove(headers, "content-length")
|
|
16
|
-
: Headers.set(headers, "content-length",
|
|
24
|
+
: Headers.set(headers, "content-length", contentLength.toString())
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
/**
|
|
@@ -3,3 +3,32 @@ import * as Redacted from "../../Redacted.ts"
|
|
|
3
3
|
/** @internal */
|
|
4
4
|
export const unwrap = (value: string | Redacted.Redacted): string =>
|
|
5
5
|
typeof value === "string" ? value : Redacted.value(value)
|
|
6
|
+
|
|
7
|
+
/** @internal */
|
|
8
|
+
export const stripSearchAndHash = (url: string): string => {
|
|
9
|
+
const queryIndex = url.indexOf("?")
|
|
10
|
+
const hashIndex = url.indexOf("#")
|
|
11
|
+
|
|
12
|
+
if (queryIndex === -1) {
|
|
13
|
+
return hashIndex === -1 ? url : url.slice(0, hashIndex)
|
|
14
|
+
}
|
|
15
|
+
if (hashIndex === -1) {
|
|
16
|
+
return url.slice(0, queryIndex)
|
|
17
|
+
}
|
|
18
|
+
return url.slice(0, Math.min(queryIndex, hashIndex))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const originForm = /^\/(?![/\\])/
|
|
22
|
+
|
|
23
|
+
/** @internal */
|
|
24
|
+
export const toPath = (url: string): string => {
|
|
25
|
+
// Origin-form targets and "*" are already paths; absolute URLs can carry credentials.
|
|
26
|
+
if (url === "*" || originForm.test(url)) {
|
|
27
|
+
return stripSearchAndHash(url)
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
return new URL(url, "http://localhost").pathname
|
|
31
|
+
} catch {
|
|
32
|
+
return "<invalid URL>"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/http-api/HttpApi.ts
CHANGED
|
@@ -371,12 +371,9 @@ export class AdditionalSchemas extends Context.Service<
|
|
|
371
371
|
*
|
|
372
372
|
* Header codecs receive all HTTP headers, including undeclared transport
|
|
373
373
|
* headers such as `content-type`, `content-length`, `host`, `user-agent` and
|
|
374
|
-
* proxy headers. Without `HeadersParseOptions`, headers use `ParseOptions
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
* responses with transport headers.
|
|
378
|
-
* - `onExcessProperty: "preserve"` includes transport headers in the decoded
|
|
379
|
-
* value.
|
|
374
|
+
* proxy headers. Without `HeadersParseOptions`, headers use `ParseOptions`, so
|
|
375
|
+
* `onExcessProperty: "error"` rejects real requests and `WithHeaders` responses
|
|
376
|
+
* with transport headers.
|
|
380
377
|
*
|
|
381
378
|
* Set `HeadersParseOptions` to `{}` at the API level to use Schema defaults for
|
|
382
379
|
* headers, even if an endpoint sets `ParseOptions`.
|