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
|
@@ -38,6 +38,14 @@ import * as ShardingConfig from "./ShardingConfig.ts"
|
|
|
38
38
|
|
|
39
39
|
const withTracerDisabled = Effect.withTracerEnabled(false)
|
|
40
40
|
|
|
41
|
+
// The session holding a storage's advisory locks, as reported to other
|
|
42
|
+
// sessions.
|
|
43
|
+
interface LockSession {
|
|
44
|
+
pid: number
|
|
45
|
+
// MySQL only: the lock that pins the session's lock connection
|
|
46
|
+
readonly pinLock: string | undefined
|
|
47
|
+
}
|
|
48
|
+
|
|
41
49
|
// This exact FNV-1a hash, including its tag and UTF-8 encoding, is a persistent
|
|
42
50
|
// advisory-lock wire format and must never change.
|
|
43
51
|
const postgresLockNamespace = (prefix: string): number => {
|
|
@@ -69,6 +77,28 @@ const makeStorage = Effect.fnUntraced(function*(options: {
|
|
|
69
77
|
// PostgreSQL exposes the signed int4 lock key through pg_locks as an unsigned oid.
|
|
70
78
|
const pgLockNamespaceOid = pgLockNamespace >>> 0
|
|
71
79
|
|
|
80
|
+
// MySQL identifies a lock holder by connection id. Behind Vitess that is the
|
|
81
|
+
// id of vtgate's lock connection for the session, which vtgate replaces
|
|
82
|
+
// once the session releases all of its locks. A lock of the session's own
|
|
83
|
+
// pins that connection and reads its id.
|
|
84
|
+
const pinLockSession = Effect.fnUntraced(function*(conn: Connection, pinLock?: string) {
|
|
85
|
+
while (true) {
|
|
86
|
+
const name = pinLock ?? `cluster:pid:${(Math.random() * Number.MAX_SAFE_INTEGER) | 0}`
|
|
87
|
+
const taken = (yield* conn.executeValues(
|
|
88
|
+
`SELECT GET_LOCK('${name}', 10), IS_USED_LOCK('${name}')`,
|
|
89
|
+
[]
|
|
90
|
+
))[0] as [1 | null, number]
|
|
91
|
+
if (taken[0] === null) continue
|
|
92
|
+
return { pid: Number(taken[1]), pinLock: name }
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
// In milliseconds, capped to the largest value PostgreSQL accepts.
|
|
97
|
+
const idleSessionTimeout = Math.min(
|
|
98
|
+
Math.ceil(Duration.toMillis(Duration.fromInputUnsafe(config.shardLockExpiration))),
|
|
99
|
+
2147483647
|
|
100
|
+
)
|
|
101
|
+
|
|
72
102
|
// Keep all PostgreSQL and MySQL shard-lock operations on a rebuildable
|
|
73
103
|
// reserved connection, including when advisory locks are disabled.
|
|
74
104
|
const acquireLockConn = singleSession ? undefined : sql.onDialectOrElse({
|
|
@@ -77,9 +107,18 @@ const makeStorage = Effect.fnUntraced(function*(options: {
|
|
|
77
107
|
const conn = yield* Effect.orDie(sql.reserve).pipe(
|
|
78
108
|
Scope.provide(scope)
|
|
79
109
|
)
|
|
110
|
+
// Advisory locks belong to the session, so a frozen runner whose
|
|
111
|
+
// connection stays open would hold them indefinitely. End the session
|
|
112
|
+
// once it has been idle for shardLockExpiration, which releases them.
|
|
113
|
+
// Runners holding shards use it at least every shardLockExpiration / 3.
|
|
114
|
+
// Servers without idle_session_timeout (before PostgreSQL 14) keep the
|
|
115
|
+
// session open.
|
|
80
116
|
const pid = disableAdvisoryLocks
|
|
81
117
|
? 0
|
|
82
|
-
: (yield* conn.executeValues(
|
|
118
|
+
: (yield* conn.executeValues(
|
|
119
|
+
`SELECT pg_backend_pid(), (SELECT set_config(name, '${idleSessionTimeout}', false) FROM pg_settings WHERE name = 'idle_session_timeout')`,
|
|
120
|
+
[]
|
|
121
|
+
))[0][0] as number
|
|
83
122
|
if (!disableAdvisoryLocks) {
|
|
84
123
|
yield* Scope.addFinalizerExit(scope, () =>
|
|
85
124
|
conn.executeRaw("SELECT pg_advisory_unlock_all()", []).pipe(
|
|
@@ -88,26 +127,17 @@ const makeStorage = Effect.fnUntraced(function*(options: {
|
|
|
88
127
|
Effect.ignoreCause
|
|
89
128
|
))
|
|
90
129
|
}
|
|
91
|
-
return [conn, pid] as const
|
|
130
|
+
return [conn, { pid, pinLock: undefined }] as const
|
|
92
131
|
}, Effect.orDie),
|
|
93
132
|
mysql: () =>
|
|
94
133
|
Effect.fnUntraced(function*(scope: Scope.Scope) {
|
|
95
134
|
const conn = yield* Effect.orDie(sql.reserve).pipe(
|
|
96
135
|
Scope.provide(scope)
|
|
97
136
|
)
|
|
98
|
-
if (disableAdvisoryLocks) return [conn, 0] as const
|
|
137
|
+
if (disableAdvisoryLocks) return [conn, { pid: 0, pinLock: undefined }] as const
|
|
99
138
|
// we need to get the connection id using IS_USED_LOCK to properly
|
|
100
139
|
// support vitess
|
|
101
|
-
|
|
102
|
-
while (pid === undefined) {
|
|
103
|
-
const address = `cluster:pid:${(Math.random() * Number.MAX_SAFE_INTEGER) | 0}`
|
|
104
|
-
const taken = (yield* conn.executeValues(
|
|
105
|
-
`SELECT GET_LOCK('${address}', 10), IS_USED_LOCK('${address}')`,
|
|
106
|
-
[]
|
|
107
|
-
))[0] as [1 | null, number]
|
|
108
|
-
if (taken[0] === null) continue
|
|
109
|
-
pid = taken[1]
|
|
110
|
-
}
|
|
140
|
+
const session: LockSession = yield* pinLockSession(conn)
|
|
111
141
|
if (!disableAdvisoryLocks) {
|
|
112
142
|
yield* Scope.addFinalizerExit(scope, () =>
|
|
113
143
|
conn.executeRaw("SELECT RELEASE_ALL_LOCKS()", []).pipe(
|
|
@@ -116,7 +146,7 @@ const makeStorage = Effect.fnUntraced(function*(options: {
|
|
|
116
146
|
Effect.ignoreCause
|
|
117
147
|
))
|
|
118
148
|
}
|
|
119
|
-
return [conn,
|
|
149
|
+
return [conn, session] as const
|
|
120
150
|
}, Effect.orDie),
|
|
121
151
|
orElse: () => undefined
|
|
122
152
|
})
|
|
@@ -140,7 +170,7 @@ const makeStorage = Effect.fnUntraced(function*(options: {
|
|
|
140
170
|
)
|
|
141
171
|
})
|
|
142
172
|
|
|
143
|
-
const rebuildLockConn = (from?: readonly [Connection,
|
|
173
|
+
const rebuildLockConn = (from?: readonly [Connection, LockSession]) => {
|
|
144
174
|
const rebuild = lockConn?.rebuildUnsafe({ from })
|
|
145
175
|
if (!rebuild) return Effect.void
|
|
146
176
|
// Bound release so a stalled connection cannot block subsequent rebuilds.
|
|
@@ -152,13 +182,13 @@ const makeStorage = Effect.fnUntraced(function*(options: {
|
|
|
152
182
|
}
|
|
153
183
|
// SQL failures replace the held connection; deadlines are handled by withLockOperationDeadline.
|
|
154
184
|
const useLockConn = <A, E, R>(
|
|
155
|
-
f: (conn: Connection, pid: number) => Effect.Effect<A, E, R>
|
|
185
|
+
f: (conn: Connection, pid: number, session: LockSession) => Effect.Effect<A, E, R>
|
|
156
186
|
): Effect.Effect<A, E, R> =>
|
|
157
187
|
Effect.flatMap(
|
|
158
188
|
lockConn!.await,
|
|
159
189
|
(held) =>
|
|
160
190
|
Effect.onError(
|
|
161
|
-
f(held[0], held[1]),
|
|
191
|
+
f(held[0], held[1].pid, held[1]),
|
|
162
192
|
(cause) => Cause.hasInterruptsOnly(cause) ? Effect.void : rebuildLockConn(held)
|
|
163
193
|
)
|
|
164
194
|
)
|
|
@@ -270,6 +300,40 @@ const makeStorage = Effect.fnUntraced(function*(options: {
|
|
|
270
300
|
return useLockConn((conn) => conn.executeValues(query, params))
|
|
271
301
|
}
|
|
272
302
|
|
|
303
|
+
// Splits shardIds into the advisory locks held by the lock session and the rest.
|
|
304
|
+
const pgHeldLocks = Effect.fnUntraced(function*(conn: Connection, pid: number, shardIds: ReadonlyArray<string>) {
|
|
305
|
+
const held: Array<string> = []
|
|
306
|
+
const notHeld = new Map(shardIds.map((shardId) => [lockNumbers.get(shardId)!, shardId]))
|
|
307
|
+
const takenLocks = yield* conn.executeValues(
|
|
308
|
+
`SELECT objid FROM pg_locks WHERE locktype = 'advisory' AND granted = true AND classid = ${pgLockNamespaceOid} AND objsubid = 2 AND pid = ${pid} ORDER BY objid`,
|
|
309
|
+
[]
|
|
310
|
+
)
|
|
311
|
+
for (let i = 0; i < takenLocks.length; i++) {
|
|
312
|
+
const lockNum = takenLocks[i][0] as number
|
|
313
|
+
const shardId = notHeld.get(lockNum)
|
|
314
|
+
if (shardId === undefined) continue
|
|
315
|
+
held.push(shardId)
|
|
316
|
+
notHeld.delete(lockNum)
|
|
317
|
+
}
|
|
318
|
+
return [held, notHeld] as const
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
const mysqlHeldLocks = Effect.fnUntraced(function*(conn: Connection, pid: number, shardIds: ReadonlyArray<string>) {
|
|
322
|
+
const takenLocks = (yield* conn.executeValues(`SELECT ${allMySqlTakenLocks}`, []))[0] as Array<number | null>
|
|
323
|
+
const held: Array<string> = []
|
|
324
|
+
const notHeld: Array<string> = []
|
|
325
|
+
for (let i = 0; i < shardIds.length; i++) {
|
|
326
|
+
const shardId = shardIds[i]
|
|
327
|
+
const lockTakenBy = takenLocks[shardIdsIndex.get(shardId)!]
|
|
328
|
+
if (lockTakenBy !== null && Number(lockTakenBy) === pid) {
|
|
329
|
+
held.push(shardId)
|
|
330
|
+
} else {
|
|
331
|
+
notHeld.push(shardId)
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return [held, notHeld] as const
|
|
335
|
+
})
|
|
336
|
+
|
|
273
337
|
const acquireLock = sql.onDialectOrElse({
|
|
274
338
|
pg: () => {
|
|
275
339
|
if (disableAdvisoryLocks) {
|
|
@@ -293,19 +357,7 @@ const makeStorage = Effect.fnUntraced(function*(options: {
|
|
|
293
357
|
}
|
|
294
358
|
return (_address: string, shardIds: ReadonlyArray<string>) =>
|
|
295
359
|
useLockConn(Effect.fnUntraced(function*(conn, pid) {
|
|
296
|
-
const acquiredShardIds
|
|
297
|
-
const toAcquire = new Map(shardIds.map((shardId) => [lockNumbers.get(shardId)!, shardId]))
|
|
298
|
-
const takenLocks = yield* conn.executeValues(
|
|
299
|
-
`SELECT objid FROM pg_locks WHERE locktype = 'advisory' AND granted = true AND classid = ${pgLockNamespaceOid} AND objsubid = 2 AND pid = ${pid} ORDER BY objid`,
|
|
300
|
-
[]
|
|
301
|
-
)
|
|
302
|
-
for (let i = 0; i < takenLocks.length; i++) {
|
|
303
|
-
const lockNum = takenLocks[i][0] as number
|
|
304
|
-
const shardId = toAcquire.get(lockNum)
|
|
305
|
-
if (shardId === undefined) continue
|
|
306
|
-
acquiredShardIds.push(shardId)
|
|
307
|
-
toAcquire.delete(lockNum)
|
|
308
|
-
}
|
|
360
|
+
const [acquiredShardIds, toAcquire] = yield* pgHeldLocks(conn, pid, shardIds)
|
|
309
361
|
if (toAcquire.size === 0) {
|
|
310
362
|
return acquiredShardIds
|
|
311
363
|
}
|
|
@@ -339,18 +391,7 @@ const makeStorage = Effect.fnUntraced(function*(options: {
|
|
|
339
391
|
}
|
|
340
392
|
return (_address: string, shardIds: ReadonlyArray<string>) =>
|
|
341
393
|
useLockConn(Effect.fnUntraced(function*(conn, pid) {
|
|
342
|
-
const
|
|
343
|
-
const acquiredShardIds: Array<string> = []
|
|
344
|
-
const toAcquire: Array<string> = []
|
|
345
|
-
for (let i = 0; i < shardIds.length; i++) {
|
|
346
|
-
const shardId = shardIds[i]
|
|
347
|
-
const lockTakenBy = takenLocks[shardIdsIndex.get(shardId)!]
|
|
348
|
-
if (lockTakenBy === pid) {
|
|
349
|
-
acquiredShardIds.push(shardId)
|
|
350
|
-
} else if (shardIds.includes(shardId)) {
|
|
351
|
-
toAcquire.push(shardId)
|
|
352
|
-
}
|
|
353
|
-
}
|
|
394
|
+
const [acquiredShardIds, toAcquire] = yield* mysqlHeldLocks(conn, pid, shardIds)
|
|
354
395
|
if (toAcquire.length === 0) {
|
|
355
396
|
return acquiredShardIds
|
|
356
397
|
}
|
|
@@ -463,9 +504,15 @@ const makeStorage = Effect.fnUntraced(function*(options: {
|
|
|
463
504
|
const stringLiteral = (s: string) => sql.literal(wrapString(s))
|
|
464
505
|
const stringLiteralArr = (arr: ReadonlyArray<string>) => sql.literal(`(${arr.map(wrapString).join(",")})`)
|
|
465
506
|
|
|
507
|
+
// An advisory lock refresh only confirms the locks the current lock session
|
|
508
|
+
// holds. A replaced session has lost its predecessor's locks, possibly to
|
|
509
|
+
// another runner in between, so reacquiring them here would hide the loss.
|
|
466
510
|
const refreshShards = sql.onDialectOrElse({
|
|
467
511
|
pg: () => {
|
|
468
|
-
if (!disableAdvisoryLocks)
|
|
512
|
+
if (!disableAdvisoryLocks) {
|
|
513
|
+
return (_address: string, shardIds: ReadonlyArray<string>) =>
|
|
514
|
+
useLockConn((conn, pid) => Effect.map(pgHeldLocks(conn, pid, shardIds), ([held]) => held))
|
|
515
|
+
}
|
|
469
516
|
return (address: string, shardIds: ReadonlyArray<string>) =>
|
|
470
517
|
sql`
|
|
471
518
|
WITH locked AS (
|
|
@@ -483,7 +530,10 @@ const makeStorage = Effect.fnUntraced(function*(options: {
|
|
|
483
530
|
)
|
|
484
531
|
},
|
|
485
532
|
mysql: () => {
|
|
486
|
-
if (!disableAdvisoryLocks)
|
|
533
|
+
if (!disableAdvisoryLocks) {
|
|
534
|
+
return (_address: string, shardIds: ReadonlyArray<string>) =>
|
|
535
|
+
useLockConn((conn, pid) => Effect.map(mysqlHeldLocks(conn, pid, shardIds), ([held]) => held))
|
|
536
|
+
}
|
|
487
537
|
return (address: string, shardIds: ReadonlyArray<string>) => {
|
|
488
538
|
const shardIdsStr = stringLiteralArr(shardIds)
|
|
489
539
|
return sql<Array<{ shard_id: string }>>`
|
|
@@ -558,7 +608,7 @@ const makeStorage = Effect.fnUntraced(function*(options: {
|
|
|
558
608
|
`SELECT IS_USED_LOCK('${lockName}')`,
|
|
559
609
|
[]
|
|
560
610
|
)
|
|
561
|
-
if (takenLocks.length === 0 || takenLocks[0][0] !== pid) return
|
|
611
|
+
if (takenLocks.length === 0 || Number(takenLocks[0][0]) !== pid) return
|
|
562
612
|
}
|
|
563
613
|
}))
|
|
564
614
|
},
|
|
@@ -579,7 +629,12 @@ const makeStorage = Effect.fnUntraced(function*(options: {
|
|
|
579
629
|
mysql: () => (address: string) =>
|
|
580
630
|
disableAdvisoryLocks
|
|
581
631
|
? sql`DELETE FROM ${locksTableSql} WHERE address = ${address}`.pipe(execWithLockConn)
|
|
582
|
-
:
|
|
632
|
+
: useLockConn(Effect.fnUntraced(function*(conn, _pid, session) {
|
|
633
|
+
yield* conn.executeRaw("SELECT RELEASE_ALL_LOCKS()", [])
|
|
634
|
+
// Releasing every lock also releases the pin, so take it again.
|
|
635
|
+
const pinned = yield* pinLockSession(conn, session.pinLock)
|
|
636
|
+
session.pid = pinned.pid
|
|
637
|
+
})),
|
|
583
638
|
orElse: () => (address: string) => sql`DELETE FROM ${locksTableSql} WHERE address = ${address}`
|
|
584
639
|
})
|
|
585
640
|
|
|
@@ -612,8 +667,16 @@ const makeStorage = Effect.fnUntraced(function*(options: {
|
|
|
612
667
|
withTracerDisabled
|
|
613
668
|
),
|
|
614
669
|
|
|
670
|
+
// A runner without shards leaves its lock connection idle, so the server
|
|
671
|
+
// may have ended the session, and the first operation on it fails and
|
|
672
|
+
// replaces it. Acquiring does not depend on the previous session, so retry
|
|
673
|
+
// once on the replacement.
|
|
615
674
|
acquire: (address, shardIds) =>
|
|
616
|
-
withLockOperationDeadline(
|
|
675
|
+
withLockOperationDeadline(
|
|
676
|
+
lockConn
|
|
677
|
+
? Effect.catch(acquireLock(address, shardIds), () => acquireLock(address, shardIds))
|
|
678
|
+
: acquireLock(address, shardIds)
|
|
679
|
+
).pipe(
|
|
617
680
|
PersistenceError.refail,
|
|
618
681
|
withTracerDisabled
|
|
619
682
|
),
|
|
@@ -20,6 +20,7 @@ import * as Schedule from "../../Schedule.ts"
|
|
|
20
20
|
import * as Schema from "../../Schema.ts"
|
|
21
21
|
import * as SchemaIssue from "../../SchemaIssue.ts"
|
|
22
22
|
import * as Scope from "../../Scope.ts"
|
|
23
|
+
import type { PersistenceError } from "../ClusterError.ts"
|
|
23
24
|
import { AlreadyProcessingMessage, EntityNotAssignedToRunner, MailboxFull, MalformedMessage } from "../ClusterError.ts"
|
|
24
25
|
import * as ClusterMetrics from "../ClusterMetrics.ts"
|
|
25
26
|
import { isUninterruptibleForServer, Persisted, WithTransaction } from "../ClusterSchema.ts"
|
|
@@ -37,6 +38,7 @@ import type { ShardId } from "../ShardId.ts"
|
|
|
37
38
|
import type { Sharding } from "../Sharding.ts"
|
|
38
39
|
import { ShardingConfig } from "../ShardingConfig.ts"
|
|
39
40
|
import * as Snowflake from "../Snowflake.ts"
|
|
41
|
+
import * as ClusterAbandon from "./clusterAbandon.ts"
|
|
40
42
|
import { CurrentActivationScope } from "./entityActivation.ts"
|
|
41
43
|
import { EntityReaper } from "./entityReaper.ts"
|
|
42
44
|
import { acquireEntity, releaseEntity } from "./interruptors.ts"
|
|
@@ -144,6 +146,19 @@ export const make = Effect.fnUntraced(function*<
|
|
|
144
146
|
readonly disableFatalDefects?: boolean | undefined
|
|
145
147
|
readonly defectRetryPolicy?: Schedule.Schedule<any, unknown, never, never> | undefined
|
|
146
148
|
readonly spanAttributes?: Record<string, string> | undefined
|
|
149
|
+
/**
|
|
150
|
+
* Called once a retiring entity stops accepting requests, so callers
|
|
151
|
+
* waiting on requests it has not started can be released.
|
|
152
|
+
*/
|
|
153
|
+
readonly abandonUndelivered: (
|
|
154
|
+
address: EntityAddress,
|
|
155
|
+
isDelivered: (requestId: Snowflake.Snowflake) => boolean
|
|
156
|
+
) => Effect.Effect<void>
|
|
157
|
+
/**
|
|
158
|
+
* Whether this runner still owns the shard, checked before storing the
|
|
159
|
+
* final reply of a persisted request.
|
|
160
|
+
*/
|
|
161
|
+
readonly isShardOwned: (shardId: ShardId) => Effect.Effect<boolean>
|
|
147
162
|
}
|
|
148
163
|
) {
|
|
149
164
|
const config = yield* ShardingConfig
|
|
@@ -248,6 +263,14 @@ export const make = Effect.fnUntraced(function*<
|
|
|
248
263
|
// Finalizers run in reverse, so the mailbox series and the resident
|
|
249
264
|
// mailbox are removed only after the drain finalizer below has finished.
|
|
250
265
|
const activeRequests: EntityState["activeRequests"] = new Map()
|
|
266
|
+
// Drops a request that has left this entity, starting the idle timer when
|
|
267
|
+
// it was the last one.
|
|
268
|
+
const removeActiveRequest = (requestId: Snowflake.Snowflake) => {
|
|
269
|
+
activeRequests.delete(requestId)
|
|
270
|
+
if (activeRequests.size === 0) {
|
|
271
|
+
state.lastActiveCheck = clock.currentTimeMillisUnsafe()
|
|
272
|
+
}
|
|
273
|
+
}
|
|
251
274
|
let mailboxSeries: Metric.Registration | undefined
|
|
252
275
|
yield* Scope.addFinalizer(
|
|
253
276
|
scope,
|
|
@@ -326,27 +349,27 @@ export const make = Effect.fnUntraced(function*<
|
|
|
326
349
|
return Effect.void
|
|
327
350
|
}
|
|
328
351
|
|
|
329
|
-
// For durable messages, ignore interrupts during shutdown.
|
|
330
|
-
// They will be retried when the entity is restarted.
|
|
331
|
-
// Also, if the request is uninterruptible, we ignore the
|
|
332
|
-
// interrupt.
|
|
333
352
|
const persisted = storageEnabled && Context.get(request.message.annotations, Persisted)
|
|
334
|
-
if (
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
353
|
+
if (persisted && Exit.isFailure(response.exit) && Cause.hasInterrupts(response.exit.cause)) {
|
|
354
|
+
// A durable request interrupted by shutdown, or abandoned
|
|
355
|
+
// because this owner can no longer serve it, is left for
|
|
356
|
+
// replay instead of being answered.
|
|
357
|
+
const abandoned = ClusterAbandon.isCause(response.exit.cause) &&
|
|
358
|
+
(!isActive() || !options.sharding.hasShardId(address.shardId))
|
|
359
|
+
if (isShuttingDown || request.terminating || abandoned) {
|
|
360
|
+
removeActiveRequest(Snowflake.Snowflake(response.requestId))
|
|
361
|
+
return options.storage.unregisterReplyHandler(request.message.envelope.requestId)
|
|
362
|
+
}
|
|
363
|
+
// An uninterruptible request ignores the interrupt and runs again.
|
|
364
|
+
if (isUninterruptibleForServer(request.message.annotations)) {
|
|
340
365
|
request.sentExit = false
|
|
341
366
|
return server.write(0, requestEnvelope(request), requestWriteOptions(request)).pipe(
|
|
342
367
|
Effect.setContext(handlerContext),
|
|
343
368
|
Effect.forkIn(handlerScope)
|
|
344
369
|
)
|
|
345
370
|
}
|
|
346
|
-
activeRequests.delete(Snowflake.Snowflake(response.requestId))
|
|
347
|
-
return options.storage.unregisterReplyHandler(request.message.envelope.requestId)
|
|
348
371
|
}
|
|
349
|
-
const
|
|
372
|
+
const write = retryRespond(
|
|
350
373
|
4,
|
|
351
374
|
Effect.suspend(() =>
|
|
352
375
|
request.message.respond(
|
|
@@ -358,18 +381,36 @@ export const make = Effect.fnUntraced(function*<
|
|
|
358
381
|
)
|
|
359
382
|
)
|
|
360
383
|
)
|
|
384
|
+
// A runner that lost the shard must not decide the stored
|
|
385
|
+
// result. A rejection is not retried.
|
|
386
|
+
let fenced = false
|
|
387
|
+
const save = !persisted ? write : Effect.flatMap(
|
|
388
|
+
options.isShardOwned(address.shardId),
|
|
389
|
+
(owned): Effect.Effect<void, MalformedMessage | PersistenceError | EntityNotAssignedToRunner> => {
|
|
390
|
+
if (owned) return write
|
|
391
|
+
fenced = true
|
|
392
|
+
return Effect.fail(new EntityNotAssignedToRunner({ address }))
|
|
393
|
+
}
|
|
394
|
+
)
|
|
395
|
+
// Leave the request for the shard's owner: release the claim
|
|
396
|
+
// so its next poll sees it, and let local callers re-route.
|
|
397
|
+
const abandonFenced = Effect.suspend(() => {
|
|
398
|
+
removeActiveRequest(Snowflake.Snowflake(response.requestId))
|
|
399
|
+
return Effect.logDebug("Abandoning a request whose shard this runner no longer owns").pipe(
|
|
400
|
+
Effect.andThen(options.storage.unregisterReplyHandler(request.message.envelope.requestId)),
|
|
401
|
+
Effect.andThen(Effect.ignore(options.storage.resetRequests([request.message.envelope.requestId])))
|
|
402
|
+
)
|
|
403
|
+
})
|
|
361
404
|
const complete = Effect.sync(() => {
|
|
362
405
|
if (storageEnabled) {
|
|
363
406
|
processedRequestIds.add(request.message.envelope.requestId)
|
|
364
407
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
// Start the idle timer when the last request completes.
|
|
368
|
-
if (activeRequests.size === 0) {
|
|
369
|
-
state.lastActiveCheck = clock.currentTimeMillisUnsafe()
|
|
370
|
-
}
|
|
408
|
+
removeActiveRequest(Snowflake.Snowflake(response.requestId))
|
|
371
409
|
})
|
|
372
|
-
const respond = Effect.
|
|
410
|
+
const respond = Effect.andThen(save, complete).pipe(
|
|
411
|
+
Effect.catchTag("EntityNotAssignedToRunner", () => abandonFenced),
|
|
412
|
+
Effect.orDie
|
|
413
|
+
)
|
|
373
414
|
const transaction = request.transaction
|
|
374
415
|
if (!transaction) return respond
|
|
375
416
|
const exit = response.exit
|
|
@@ -381,8 +422,12 @@ export const make = Effect.fnUntraced(function*<
|
|
|
381
422
|
}
|
|
382
423
|
|
|
383
424
|
if (Exit.isSuccess(exit)) {
|
|
384
|
-
transaction.settle = (outcome) =>
|
|
385
|
-
Exit.isSuccess(outcome)
|
|
425
|
+
transaction.settle = (outcome) => {
|
|
426
|
+
if (Exit.isSuccess(outcome)) return complete
|
|
427
|
+
// A rejected save failed the transaction, rolling back the
|
|
428
|
+
// handler's writes; the request is left for the owner.
|
|
429
|
+
if (fenced) return abandonFenced
|
|
430
|
+
return Effect.flatMap(
|
|
386
431
|
hasStoredExit(request.message.envelope.requestId),
|
|
387
432
|
(committed) => {
|
|
388
433
|
if (!committed) return restartFrom(outcome.cause)
|
|
@@ -393,6 +438,7 @@ export const make = Effect.fnUntraced(function*<
|
|
|
393
438
|
)
|
|
394
439
|
}
|
|
395
440
|
)
|
|
441
|
+
}
|
|
396
442
|
return Effect.orDie(save)
|
|
397
443
|
}
|
|
398
444
|
transaction.settle = (outcome) =>
|
|
@@ -539,6 +585,13 @@ export const make = Effect.fnUntraced(function*<
|
|
|
539
585
|
request.terminating = true
|
|
540
586
|
yield* state.write(0, { _tag: "Interrupt", requestId: requestId as any, interruptors: [] })
|
|
541
587
|
}
|
|
588
|
+
// A handler this drain waits for may be parked on a request the
|
|
589
|
+
// retired entity will never start, such as its own queued request.
|
|
590
|
+
// Release callers before `Eof`, which waits for handler acquisition.
|
|
591
|
+
yield* options.abandonUndelivered(
|
|
592
|
+
address,
|
|
593
|
+
(requestId) => activeRequests.get(requestId)?.delivered === true
|
|
594
|
+
)
|
|
542
595
|
yield* state.write(0, { _tag: "Eof" })
|
|
543
596
|
}).pipe(
|
|
544
597
|
Effect.andThen(endLatch.await),
|
|
@@ -219,6 +219,7 @@ const makeTracerEffect = Effect.gen(function*() {
|
|
|
219
219
|
client.sendUnsafe(spanSnapshot(span))
|
|
220
220
|
const oldEvent = span.event
|
|
221
221
|
span.event = function(this: Tracer.Span, name, startTime, attributes) {
|
|
222
|
+
if (span.status._tag === "Ended") return
|
|
222
223
|
client.sendUnsafe({
|
|
223
224
|
_tag: "SpanEvent",
|
|
224
225
|
traceId: span.traceId,
|
|
@@ -232,6 +233,7 @@ const makeTracerEffect = Effect.gen(function*() {
|
|
|
232
233
|
|
|
233
234
|
const oldEnd = span.end
|
|
234
235
|
span.end = function(this: Tracer.Span, endTime, exit) {
|
|
236
|
+
if (span.status._tag === "Ended") return
|
|
235
237
|
oldEnd.call(this, endTime, exit)
|
|
236
238
|
client.sendUnsafe(spanSnapshot(span))
|
|
237
239
|
}
|
package/src/encoding/Base64.ts
CHANGED
|
@@ -148,6 +148,16 @@ export const decode = (str: string): Result.Result<Uint8Array, EncodingError> =>
|
|
|
148
148
|
export const decodeString = (str: string) => Result.map(decode(str), (_) => decoder.decode(_))
|
|
149
149
|
|
|
150
150
|
const encodeBytes = (bytes: Uint8Array): string => {
|
|
151
|
+
const length = bytes.length
|
|
152
|
+
// Looked up on the prototype at call time, so own or subclass overrides are ignored.
|
|
153
|
+
const toBase64 = (Uint8Array.prototype as { readonly toBase64?: (this: Uint8Array) => string }).toBase64
|
|
154
|
+
// The size guard also keeps detached buffers (length 0) away from native `toBase64`, which throws on them.
|
|
155
|
+
if (length >= 32 && typeof toBase64 === "function") return toBase64.call(bytes)
|
|
156
|
+
// Below ~128 bytes, appending to a string beats filling a byte array and decoding it once.
|
|
157
|
+
return length < 128 ? encodeShort(bytes) : encodeLong(bytes)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const encodeShort = (bytes: Uint8Array): string => {
|
|
151
161
|
const length = bytes.length
|
|
152
162
|
let result = ""
|
|
153
163
|
let i: number
|
|
@@ -171,10 +181,38 @@ const encodeBytes = (bytes: Uint8Array): string => {
|
|
|
171
181
|
return result
|
|
172
182
|
}
|
|
173
183
|
|
|
184
|
+
const encodeLong = (bytes: Uint8Array): string => {
|
|
185
|
+
const length = bytes.length
|
|
186
|
+
const result = new Uint8Array(Math.ceil(length / 3) * 4)
|
|
187
|
+
let i: number
|
|
188
|
+
let j = 0
|
|
189
|
+
for (i = 2; i < length; i += 3, j += 4) {
|
|
190
|
+
result[j] = alphabetCodes[bytes[i - 2] >> 2]
|
|
191
|
+
result[j + 1] = alphabetCodes[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)]
|
|
192
|
+
result[j + 2] = alphabetCodes[((bytes[i - 1] & 0x0f) << 2) | (bytes[i] >> 6)]
|
|
193
|
+
result[j + 3] = alphabetCodes[bytes[i] & 0x3f]
|
|
194
|
+
}
|
|
195
|
+
if (i === length + 1) {
|
|
196
|
+
result[j] = alphabetCodes[bytes[i - 2] >> 2]
|
|
197
|
+
result[j + 1] = alphabetCodes[(bytes[i - 2] & 0x03) << 4]
|
|
198
|
+
result[j + 2] = paddingCode
|
|
199
|
+
result[j + 3] = paddingCode
|
|
200
|
+
}
|
|
201
|
+
if (i === length) {
|
|
202
|
+
result[j] = alphabetCodes[bytes[i - 2] >> 2]
|
|
203
|
+
result[j + 1] = alphabetCodes[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)]
|
|
204
|
+
result[j + 2] = alphabetCodes[(bytes[i - 1] & 0x0f) << 2]
|
|
205
|
+
result[j + 3] = paddingCode
|
|
206
|
+
}
|
|
207
|
+
return decoder.decode(result)
|
|
208
|
+
}
|
|
209
|
+
|
|
174
210
|
const encoder = new TextEncoder()
|
|
175
211
|
const decoder = new TextDecoder()
|
|
176
212
|
const stripCrlf = (str: string) => str.replace(/[\n\r]/g, "")
|
|
177
213
|
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
|
214
|
+
const alphabetCodes = encoder.encode(alphabet)
|
|
215
|
+
const paddingCode = "=".charCodeAt(0)
|
|
178
216
|
const codes = new Uint8Array(123).fill(255)
|
|
179
217
|
for (let i = 0; i < alphabet.length; i++) codes[alphabet.charCodeAt(i)] = i
|
|
180
218
|
codes["=".charCodeAt(0)] = 0
|
package/src/encoding/Sse.ts
CHANGED
|
@@ -308,9 +308,10 @@ export function makeParser(onParse: (event: AnyEvent) => void, options?: DecodeO
|
|
|
308
308
|
}
|
|
309
309
|
|
|
310
310
|
function feed(chunk: string): SseError | undefined {
|
|
311
|
-
//
|
|
312
|
-
|
|
313
|
-
|
|
311
|
+
// Empty chunks must not consume the leading BOM check below
|
|
312
|
+
if (chunk.length === 0) return
|
|
313
|
+
|
|
314
|
+
// Strip a UTF-8 byte order mark (BOM) at the start of the stream
|
|
314
315
|
if (isFirstChunk && chunk.startsWith(BOM)) {
|
|
315
316
|
chunk = chunk.slice(BOM.length)
|
|
316
317
|
}
|
package/src/encoding/Toml.ts
CHANGED
|
@@ -47,6 +47,8 @@ class TomlParser {
|
|
|
47
47
|
private line = 1
|
|
48
48
|
private column = 1
|
|
49
49
|
private readonly explicitTables = new Set<Table>()
|
|
50
|
+
// Tables defined by dotted keys; a header cannot define them again.
|
|
51
|
+
private readonly dottedTables = new Set<Table>()
|
|
50
52
|
|
|
51
53
|
constructor(input: string) {
|
|
52
54
|
this.input = input
|
|
@@ -87,7 +89,7 @@ class TomlParser {
|
|
|
87
89
|
this.finishStatement()
|
|
88
90
|
|
|
89
91
|
const table = this.resolveTable(path, array)
|
|
90
|
-
if (!array && this.explicitTables.has(table)) {
|
|
92
|
+
if (!array && (this.explicitTables.has(table) || this.dottedTables.has(table))) {
|
|
91
93
|
this.fail(`Cannot redefine table '${path.join(".")}'`)
|
|
92
94
|
}
|
|
93
95
|
if (!array) {
|
|
@@ -120,7 +122,7 @@ class TomlParser {
|
|
|
120
122
|
value = makeTable()
|
|
121
123
|
table[key] = value
|
|
122
124
|
}
|
|
123
|
-
if (Array.isArray(value)) {
|
|
125
|
+
if (Array.isArray(value) && !last) {
|
|
124
126
|
value = value[value.length - 1]
|
|
125
127
|
}
|
|
126
128
|
if (!isTable(value)) {
|
|
@@ -140,11 +142,12 @@ class TomlParser {
|
|
|
140
142
|
const child = makeTable()
|
|
141
143
|
table[key] = child
|
|
142
144
|
table = child
|
|
143
|
-
} else if (isTable(existing)) {
|
|
145
|
+
} else if (isTable(existing) && !this.explicitTables.has(existing)) {
|
|
144
146
|
table = existing
|
|
145
147
|
} else {
|
|
146
148
|
this.fail(`Cannot redefine existing key '${keys.slice(0, index + 1).join(".")}'`)
|
|
147
149
|
}
|
|
150
|
+
this.dottedTables.add(table)
|
|
148
151
|
}
|
|
149
152
|
const key = keys[keys.length - 1]
|
|
150
153
|
if (hasOwn.call(table, key)) {
|
|
@@ -255,17 +258,17 @@ class TomlParser {
|
|
|
255
258
|
if (normalized.endsWith("nan")) return Number.NaN
|
|
256
259
|
return normalized[0] === "-" ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY
|
|
257
260
|
}
|
|
258
|
-
if (
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
return
|
|
261
|
+
if (
|
|
262
|
+
/^0x[0-9A-Fa-f](?:_?[0-9A-Fa-f])*$/.test(token) ||
|
|
263
|
+
/^0o[0-7](?:_?[0-7])*$/.test(token) ||
|
|
264
|
+
/^0b[01](?:_?[01])*$/.test(token) ||
|
|
265
|
+
/^[+-]?(?:0|[1-9](?:_?\d)*)$/.test(token)
|
|
266
|
+
) {
|
|
267
|
+
const value = Number(normalized)
|
|
268
|
+
if (!Number.isSafeInteger(value)) {
|
|
269
|
+
this.fail(`Integer out of range '${token}'`)
|
|
270
|
+
}
|
|
271
|
+
return value
|
|
269
272
|
}
|
|
270
273
|
if (
|
|
271
274
|
/^[+-]?(?:(?:0|[1-9](?:_?\d)*)\.\d(?:_?\d)*(?:[eE][+-]?\d(?:_?\d)*)?|(?:0|[1-9](?:_?\d)*)[eE][+-]?\d(?:_?\d)*)$/
|
|
@@ -330,10 +333,15 @@ class TomlParser {
|
|
|
330
333
|
} else if (escape === "u" || escape === "U") {
|
|
331
334
|
const length = escape === "u" ? 4 : 8
|
|
332
335
|
const hex = this.input.slice(this.index, this.index + length)
|
|
333
|
-
|
|
336
|
+
const codePoint = Number.parseInt(hex, 16)
|
|
337
|
+
if (
|
|
338
|
+
!new RegExp(`^[0-9A-Fa-f]{${length}}$`).test(hex) ||
|
|
339
|
+
(codePoint >= 0xD800 && codePoint <= 0xDFFF) ||
|
|
340
|
+
codePoint > 0x10FFFF
|
|
341
|
+
) {
|
|
334
342
|
this.fail("Invalid unicode escape")
|
|
335
343
|
}
|
|
336
|
-
output += String.fromCodePoint(
|
|
344
|
+
output += String.fromCodePoint(codePoint)
|
|
337
345
|
this.advance(length)
|
|
338
346
|
} else {
|
|
339
347
|
this.fail(`Invalid escape '\\${escape}'`)
|
|
@@ -470,9 +478,18 @@ class TomlParser {
|
|
|
470
478
|
|
|
471
479
|
private advance(count = 1): void {
|
|
472
480
|
for (let offset = 0; offset < count; offset++) {
|
|
481
|
+
const code = this.input.charCodeAt(this.index)
|
|
482
|
+
if (
|
|
483
|
+
(code < 0x20 && code !== 0x09 && code !== 0x0A && !(code === 0x0D && this.input[this.index + 1] === "\n")) ||
|
|
484
|
+
code === 0x7F
|
|
485
|
+
) {
|
|
486
|
+
this.fail("Invalid control character")
|
|
487
|
+
}
|
|
473
488
|
if (this.input[this.index] === "\n") {
|
|
474
489
|
this.line++
|
|
475
490
|
this.column = 1
|
|
491
|
+
} else if (this.input[this.index] === "\r" && this.input[this.index + 1] !== "\n") {
|
|
492
|
+
this.fail("Bare carriage return")
|
|
476
493
|
} else {
|
|
477
494
|
this.column++
|
|
478
495
|
}
|