effect 4.0.2 → 4.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +24 -0
- package/CLAUDE.md +24 -0
- package/ai-docs/package.json +2 -2
- package/ai-docs/src/52_graphql/10_basics.ts +111 -0
- package/ai-docs/src/52_graphql/20_testing.ts +45 -0
- package/ai-docs/src/52_graphql/30_batching.ts +116 -0
- package/ai-docs/src/52_graphql/40_aliased-batching.ts +122 -0
- package/ai-docs/src/52_graphql/50_errors-and-retries.ts +74 -0
- package/ai-docs/src/52_graphql/index.md +6 -0
- package/dist/Context.d.ts.map +1 -1
- package/dist/Context.js +12 -3
- package/dist/Context.js.map +1 -1
- package/dist/Crypto.d.ts +33 -5
- package/dist/Crypto.d.ts.map +1 -1
- package/dist/Crypto.js +8 -2
- package/dist/Crypto.js.map +1 -1
- package/dist/DateTime.d.ts +9 -6
- package/dist/DateTime.d.ts.map +1 -1
- package/dist/DateTime.js +9 -6
- package/dist/DateTime.js.map +1 -1
- package/dist/Duration.d.ts +6 -6
- package/dist/Duration.d.ts.map +1 -1
- package/dist/Duration.js +27 -8
- package/dist/Duration.js.map +1 -1
- package/dist/FileSystem.d.ts +44 -2
- package/dist/FileSystem.d.ts.map +1 -1
- package/dist/FileSystem.js.map +1 -1
- package/dist/RequestResolver.d.ts.map +1 -1
- package/dist/RequestResolver.js +4 -10
- package/dist/RequestResolver.js.map +1 -1
- package/dist/Scheduler.d.ts +9 -0
- package/dist/Scheduler.d.ts.map +1 -1
- package/dist/Scheduler.js +9 -0
- package/dist/Scheduler.js.map +1 -1
- package/dist/Schema.d.ts +481 -1
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +362 -4
- package/dist/Schema.js.map +1 -1
- package/dist/SchemaGetter.d.ts +4 -0
- package/dist/SchemaGetter.d.ts.map +1 -1
- package/dist/SchemaGetter.js +52 -33
- package/dist/SchemaGetter.js.map +1 -1
- package/dist/Sink.d.ts.map +1 -1
- package/dist/Sink.js +38 -17
- package/dist/Sink.js.map +1 -1
- package/dist/Stdio.d.ts +7 -1
- package/dist/Stdio.d.ts.map +1 -1
- package/dist/Stdio.js +1 -0
- package/dist/Stdio.js.map +1 -1
- package/dist/Stream.d.ts +22 -11
- package/dist/Stream.d.ts.map +1 -1
- package/dist/Stream.js +21 -6
- package/dist/Stream.js.map +1 -1
- package/dist/Utils.js +8 -3
- package/dist/Utils.js.map +1 -1
- package/dist/ai/AnthropicStructuredOutput.js +0 -2
- package/dist/ai/AnthropicStructuredOutput.js.map +1 -1
- package/dist/ai/Chat.d.ts +2 -2
- package/dist/ai/Chat.d.ts.map +1 -1
- package/dist/ai/LanguageModel.d.ts +38 -7
- package/dist/ai/LanguageModel.d.ts.map +1 -1
- package/dist/ai/LanguageModel.js +25 -7
- package/dist/ai/LanguageModel.js.map +1 -1
- package/dist/ai/McpServer.d.ts +61 -0
- package/dist/ai/McpServer.d.ts.map +1 -1
- package/dist/ai/McpServer.js +196 -44
- package/dist/ai/McpServer.js.map +1 -1
- package/dist/ai/Prompt.d.ts.map +1 -1
- package/dist/ai/Prompt.js +28 -5
- package/dist/ai/Prompt.js.map +1 -1
- package/dist/ai/Response.d.ts +4 -3
- package/dist/ai/Response.d.ts.map +1 -1
- package/dist/ai/Response.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2026_07_28.js +5 -0
- package/dist/ai/internal/mcpProtocol/v2026_07_28.js.map +1 -1
- package/dist/ai/internal/mcpProtocol.js.map +1 -1
- package/dist/ai/internal/mcpRuntime.js +1 -0
- package/dist/ai/internal/mcpRuntime.js.map +1 -1
- package/dist/cli/CliOutput.d.ts +27 -0
- package/dist/cli/CliOutput.d.ts.map +1 -1
- package/dist/cli/CliOutput.js +33 -10
- package/dist/cli/CliOutput.js.map +1 -1
- package/dist/cli/Command.d.ts.map +1 -1
- package/dist/cli/Command.js +6 -3
- package/dist/cli/Command.js.map +1 -1
- package/dist/cli/Completions.d.ts +3 -3
- package/dist/cli/Completions.d.ts.map +1 -1
- package/dist/cli/Completions.js +8 -5
- package/dist/cli/Completions.js.map +1 -1
- package/dist/cli/GlobalFlag.d.ts +5 -4
- package/dist/cli/GlobalFlag.d.ts.map +1 -1
- package/dist/cli/GlobalFlag.js +3 -3
- package/dist/cli/GlobalFlag.js.map +1 -1
- package/dist/cli/Prompt.d.ts +17 -1
- package/dist/cli/Prompt.d.ts.map +1 -1
- package/dist/cli/Prompt.js +119 -114
- package/dist/cli/Prompt.js.map +1 -1
- package/dist/cli/internal/ansi.d.ts +0 -1
- package/dist/cli/internal/ansi.d.ts.map +1 -1
- package/dist/cli/internal/ansi.js +20 -3
- package/dist/cli/internal/ansi.js.map +1 -1
- package/dist/cli/internal/completions/powershell.d.ts +2 -0
- package/dist/cli/internal/completions/powershell.d.ts.map +1 -0
- package/dist/cli/internal/completions/powershell.js +273 -0
- package/dist/cli/internal/completions/powershell.js.map +1 -0
- package/dist/cli/internal/completions/zsh.js +3 -2
- package/dist/cli/internal/completions/zsh.js.map +1 -1
- package/dist/cli/internal/wizard.d.ts +3 -3
- package/dist/cli/internal/wizard.d.ts.map +1 -1
- package/dist/cli/internal/wizard.js +21 -18
- package/dist/cli/internal/wizard.js.map +1 -1
- package/dist/cluster/ClusterSchema.d.ts +28 -0
- package/dist/cluster/ClusterSchema.d.ts.map +1 -1
- package/dist/cluster/ClusterSchema.js +30 -0
- package/dist/cluster/ClusterSchema.js.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.js +56 -26
- package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
- package/dist/cluster/MessageStorage.d.ts +18 -3
- package/dist/cluster/MessageStorage.d.ts.map +1 -1
- package/dist/cluster/MessageStorage.js +31 -11
- package/dist/cluster/MessageStorage.js.map +1 -1
- package/dist/cluster/Runners.d.ts.map +1 -1
- package/dist/cluster/Runners.js +8 -2
- package/dist/cluster/Runners.js.map +1 -1
- package/dist/cluster/Sharding.d.ts.map +1 -1
- package/dist/cluster/Sharding.js +187 -66
- package/dist/cluster/Sharding.js.map +1 -1
- package/dist/cluster/SqlMessageStorage.d.ts +59 -19
- package/dist/cluster/SqlMessageStorage.d.ts.map +1 -1
- package/dist/cluster/SqlMessageStorage.js +84 -55
- package/dist/cluster/SqlMessageStorage.js.map +1 -1
- package/dist/cluster/SqlRunnerStorage.d.ts +68 -19
- package/dist/cluster/SqlRunnerStorage.d.ts.map +1 -1
- package/dist/cluster/SqlRunnerStorage.js +191 -113
- package/dist/cluster/SqlRunnerStorage.js.map +1 -1
- package/dist/cluster/internal/entityManager.js +104 -37
- package/dist/cluster/internal/entityManager.js.map +1 -1
- package/dist/encoding/Sse.d.ts +6 -0
- package/dist/encoding/Sse.d.ts.map +1 -1
- package/dist/encoding/Sse.js +62 -70
- package/dist/encoding/Sse.js.map +1 -1
- package/dist/graphql/GraphQL.d.ts +349 -0
- package/dist/graphql/GraphQL.d.ts.map +1 -0
- package/dist/graphql/GraphQL.js +207 -0
- package/dist/graphql/GraphQL.js.map +1 -0
- package/dist/graphql/GraphQLClient.d.ts +562 -0
- package/dist/graphql/GraphQLClient.d.ts.map +1 -0
- package/dist/graphql/GraphQLClient.js +498 -0
- package/dist/graphql/GraphQLClient.js.map +1 -0
- package/dist/graphql/GraphQLClientError.d.ts +445 -0
- package/dist/graphql/GraphQLClientError.d.ts.map +1 -0
- package/dist/graphql/GraphQLClientError.js +479 -0
- package/dist/graphql/GraphQLClientError.js.map +1 -0
- package/dist/graphql/GraphQLGroup.d.ts +118 -0
- package/dist/graphql/GraphQLGroup.d.ts.map +1 -0
- package/dist/graphql/GraphQLGroup.js +109 -0
- package/dist/graphql/GraphQLGroup.js.map +1 -0
- package/dist/graphql/GraphQLMiddleware.d.ts +249 -0
- package/dist/graphql/GraphQLMiddleware.d.ts.map +1 -0
- package/dist/graphql/GraphQLMiddleware.js +130 -0
- package/dist/graphql/GraphQLMiddleware.js.map +1 -0
- package/dist/graphql/GraphQLProtocol.d.ts +731 -0
- package/dist/graphql/GraphQLProtocol.d.ts.map +1 -0
- package/dist/graphql/GraphQLProtocol.js +719 -0
- package/dist/graphql/GraphQLProtocol.js.map +1 -0
- package/dist/graphql/GraphQLResolver.d.ts +453 -0
- package/dist/graphql/GraphQLResolver.d.ts.map +1 -0
- package/dist/graphql/GraphQLResolver.js +552 -0
- package/dist/graphql/GraphQLResolver.js.map +1 -0
- package/dist/graphql/index.d.ts +40 -0
- package/dist/graphql/index.d.ts.map +1 -0
- package/dist/graphql/index.js +41 -0
- package/dist/graphql/index.js.map +1 -0
- package/dist/http/FindMyWay/internal/router.js +3 -6
- package/dist/http/FindMyWay/internal/router.js.map +1 -1
- package/dist/http/HttpClient.d.ts +21 -0
- package/dist/http/HttpClient.d.ts.map +1 -1
- package/dist/http/HttpClient.js +63 -12
- package/dist/http/HttpClient.js.map +1 -1
- package/dist/http/HttpEffect.d.ts.map +1 -1
- package/dist/http/HttpEffect.js +14 -7
- package/dist/http/HttpEffect.js.map +1 -1
- package/dist/http/HttpMiddleware.d.ts.map +1 -1
- package/dist/http/HttpMiddleware.js +31 -32
- package/dist/http/HttpMiddleware.js.map +1 -1
- package/dist/http/HttpRouter.d.ts +35 -0
- package/dist/http/HttpRouter.d.ts.map +1 -1
- package/dist/http/HttpRouter.js +35 -0
- package/dist/http/HttpRouter.js.map +1 -1
- package/dist/http/HttpServerResponse.d.ts +8 -6
- package/dist/http/HttpServerResponse.d.ts.map +1 -1
- package/dist/http/HttpServerResponse.js +27 -16
- package/dist/http/HttpServerResponse.js.map +1 -1
- package/dist/http/HttpTraceContext.d.ts.map +1 -1
- package/dist/http/HttpTraceContext.js +4 -2
- package/dist/http/HttpTraceContext.js.map +1 -1
- package/dist/http/Multipart.d.ts.map +1 -1
- package/dist/http/Multipart.js +15 -1
- package/dist/http/Multipart.js.map +1 -1
- package/dist/http-api/HttpApiScalar.d.ts +5 -0
- package/dist/http-api/HttpApiScalar.d.ts.map +1 -1
- package/dist/http-api/HttpApiScalar.js.map +1 -1
- package/dist/internal/dateTime.js +40 -35
- package/dist/internal/dateTime.js.map +1 -1
- package/dist/internal/effect.js +19 -9
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/graphql.d.ts +2 -0
- package/dist/internal/graphql.d.ts.map +1 -0
- package/dist/internal/graphql.js +195 -0
- package/dist/internal/graphql.js.map +1 -0
- package/dist/internal/graphqlHeaders.d.ts +4 -0
- package/dist/internal/graphqlHeaders.d.ts.map +1 -0
- package/dist/internal/graphqlHeaders.js +11 -0
- package/dist/internal/graphqlHeaders.js.map +1 -0
- package/dist/internal/request.js +20 -1
- package/dist/internal/request.js.map +1 -1
- package/dist/internal/schema/toCodeDocument.js +4 -1
- package/dist/internal/schema/toCodeDocument.js.map +1 -1
- package/dist/internal/schema/toJsonSchemaDocument.js +29 -5
- package/dist/internal/schema/toJsonSchemaDocument.js.map +1 -1
- package/dist/internal/version.js +1 -1
- package/dist/net/AddressResolver.d.ts +145 -0
- package/dist/net/AddressResolver.d.ts.map +1 -0
- package/dist/net/AddressResolver.js +114 -0
- package/dist/net/AddressResolver.js.map +1 -0
- package/dist/net/Dns.d.ts +596 -0
- package/dist/net/Dns.d.ts.map +1 -0
- package/dist/net/Dns.js +549 -0
- package/dist/net/Dns.js.map +1 -0
- package/dist/net/Host.d.ts +369 -0
- package/dist/net/Host.d.ts.map +1 -0
- package/dist/net/Host.js +397 -0
- package/dist/net/Host.js.map +1 -0
- package/dist/net/IpInterface.d.ts +76 -3
- package/dist/net/IpInterface.d.ts.map +1 -1
- package/dist/net/IpInterface.js +53 -4
- package/dist/net/IpInterface.js.map +1 -1
- package/dist/net/IpNetwork.d.ts +82 -8
- package/dist/net/IpNetwork.d.ts.map +1 -1
- package/dist/net/IpNetwork.js +60 -4
- package/dist/net/IpNetwork.js.map +1 -1
- package/dist/net/NetAddress.d.ts +396 -35
- package/dist/net/NetAddress.d.ts.map +1 -1
- package/dist/net/NetAddress.js +358 -34
- package/dist/net/NetAddress.js.map +1 -1
- package/dist/net/index.d.ts +15 -0
- package/dist/net/index.d.ts.map +1 -1
- package/dist/net/index.js +15 -0
- package/dist/net/index.js.map +1 -1
- package/dist/observability/OtlpMetrics.d.ts.map +1 -1
- package/dist/observability/OtlpMetrics.js +15 -21
- package/dist/observability/OtlpMetrics.js.map +1 -1
- package/dist/observability/PrometheusMetrics.js +1 -0
- package/dist/observability/PrometheusMetrics.js.map +1 -1
- package/dist/persistence/PersistedQueue.d.ts +32 -3
- package/dist/persistence/PersistedQueue.d.ts.map +1 -1
- package/dist/persistence/PersistedQueue.js +75 -16
- package/dist/persistence/PersistedQueue.js.map +1 -1
- package/dist/rpc/RpcClient.d.ts +22 -6
- package/dist/rpc/RpcClient.d.ts.map +1 -1
- package/dist/rpc/RpcClient.js +12 -5
- package/dist/rpc/RpcClient.js.map +1 -1
- package/dist/rpc/RpcServer.d.ts +6 -0
- package/dist/rpc/RpcServer.d.ts.map +1 -1
- package/dist/rpc/RpcServer.js +78 -29
- package/dist/rpc/RpcServer.js.map +1 -1
- package/dist/socket/DatagramSocket.d.ts +456 -0
- package/dist/socket/DatagramSocket.d.ts.map +1 -0
- package/dist/socket/DatagramSocket.js +535 -0
- package/dist/socket/DatagramSocket.js.map +1 -0
- package/dist/socket/Socket.d.ts +20 -1
- package/dist/socket/Socket.d.ts.map +1 -1
- package/dist/socket/Socket.js +9 -1
- package/dist/socket/Socket.js.map +1 -1
- package/dist/socket/index.d.ts +5 -0
- package/dist/socket/index.d.ts.map +1 -1
- package/dist/socket/index.js +5 -0
- package/dist/socket/index.js.map +1 -1
- package/dist/sql/Migrator.d.ts.map +1 -1
- package/dist/sql/Migrator.js +7 -2
- package/dist/sql/Migrator.js.map +1 -1
- package/dist/sql/SqlClient.d.ts +7 -1
- package/dist/sql/SqlClient.d.ts.map +1 -1
- package/dist/sql/SqlClient.js +31 -6
- package/dist/sql/SqlClient.js.map +1 -1
- package/dist/testing/TestCrypto.d.ts +73 -0
- package/dist/testing/TestCrypto.d.ts.map +1 -0
- package/dist/testing/TestCrypto.js +87 -0
- package/dist/testing/TestCrypto.js.map +1 -0
- package/dist/testing/index.d.ts +5 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +5 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/workflow/DurableDeferred.d.ts +54 -0
- package/dist/workflow/DurableDeferred.d.ts.map +1 -1
- package/dist/workflow/DurableDeferred.js +108 -50
- package/dist/workflow/DurableDeferred.js.map +1 -1
- package/dist/workflow/WorkflowEngine.d.ts +24 -2
- package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
- package/dist/workflow/WorkflowEngine.js +13 -3
- package/dist/workflow/WorkflowEngine.js.map +1 -1
- package/package.json +6 -3
- package/src/Context.ts +12 -3
- package/src/Crypto.ts +43 -9
- package/src/DateTime.ts +9 -6
- package/src/Duration.ts +36 -16
- package/src/FileSystem.ts +48 -2
- package/src/RequestResolver.ts +4 -10
- package/src/Scheduler.ts +9 -0
- package/src/Schema.ts +677 -5
- package/src/SchemaGetter.ts +47 -35
- package/src/Sink.ts +45 -18
- package/src/Stdio.ts +9 -2
- package/src/Stream.ts +44 -15
- package/src/Utils.ts +8 -5
- package/src/ai/AnthropicStructuredOutput.ts +2 -2
- package/src/ai/Chat.ts +2 -2
- package/src/ai/LanguageModel.ts +96 -24
- package/src/ai/McpServer.ts +288 -94
- package/src/ai/Prompt.ts +24 -10
- package/src/ai/Response.ts +6 -3
- package/src/ai/internal/mcpProtocol/v2026_07_28.ts +5 -0
- package/src/ai/internal/mcpProtocol.ts +3 -0
- package/src/ai/internal/mcpRuntime.ts +2 -0
- package/src/cli/CliOutput.ts +33 -16
- package/src/cli/Command.ts +4 -3
- package/src/cli/Completions.ts +9 -6
- package/src/cli/GlobalFlag.ts +19 -11
- package/src/cli/Prompt.ts +159 -149
- package/src/cli/internal/ansi.ts +26 -3
- package/src/cli/internal/completions/powershell.ts +322 -0
- package/src/cli/internal/completions/zsh.ts +4 -2
- package/src/cli/internal/wizard.ts +34 -26
- package/src/cluster/ClusterSchema.ts +32 -0
- package/src/cluster/ClusterWorkflowEngine.ts +64 -36
- package/src/cluster/MessageStorage.ts +45 -14
- package/src/cluster/Runners.ts +8 -2
- package/src/cluster/Sharding.ts +219 -58
- package/src/cluster/SqlMessageStorage.ts +118 -84
- package/src/cluster/SqlRunnerStorage.ts +224 -128
- package/src/cluster/internal/entityManager.ts +151 -55
- package/src/encoding/Sse.ts +69 -79
- package/src/graphql/GraphQL.ts +494 -0
- package/src/graphql/GraphQLClient.ts +912 -0
- package/src/graphql/GraphQLClientError.ts +542 -0
- package/src/graphql/GraphQLGroup.ts +167 -0
- package/src/graphql/GraphQLMiddleware.ts +253 -0
- package/src/graphql/GraphQLProtocol.ts +1286 -0
- package/src/graphql/GraphQLResolver.ts +1010 -0
- package/src/graphql/index.ts +48 -0
- package/src/http/FindMyWay/internal/router.ts +4 -7
- package/src/http/HttpClient.ts +110 -12
- package/src/http/HttpEffect.ts +11 -5
- package/src/http/HttpMiddleware.ts +33 -34
- package/src/http/HttpRouter.ts +35 -0
- package/src/http/HttpServerResponse.ts +28 -16
- package/src/http/HttpTraceContext.ts +8 -2
- package/src/http/Multipart.ts +17 -1
- package/src/http-api/HttpApiScalar.ts +5 -0
- package/src/internal/dateTime.ts +13 -10
- package/src/internal/effect.ts +22 -15
- package/src/internal/graphql.ts +263 -0
- package/src/internal/graphqlHeaders.ts +11 -0
- package/src/internal/request.ts +31 -3
- package/src/internal/schema/toCodeDocument.ts +7 -1
- package/src/internal/schema/toJsonSchemaDocument.ts +34 -2
- package/src/internal/version.ts +1 -1
- package/src/net/AddressResolver.ts +222 -0
- package/src/net/Dns.ts +1035 -0
- package/src/net/Host.ts +544 -0
- package/src/net/IpInterface.ts +117 -7
- package/src/net/IpNetwork.ts +116 -17
- package/src/net/NetAddress.ts +620 -76
- package/src/net/index.ts +18 -0
- package/src/observability/OtlpMetrics.ts +12 -23
- package/src/observability/PrometheusMetrics.ts +1 -0
- package/src/persistence/PersistedQueue.ts +146 -53
- package/src/rpc/RpcClient.ts +41 -19
- package/src/rpc/RpcServer.ts +115 -40
- package/src/socket/DatagramSocket.ts +919 -0
- package/src/socket/Socket.ts +28 -2
- package/src/socket/index.ts +6 -0
- package/src/sql/Migrator.ts +21 -5
- package/src/sql/SqlClient.ts +39 -15
- package/src/testing/TestCrypto.ts +94 -0
- package/src/testing/index.ts +6 -0
- package/src/workflow/DurableDeferred.ts +160 -47
- package/src/workflow/WorkflowEngine.ts +50 -5
package/src/internal/dateTime.ts
CHANGED
|
@@ -934,10 +934,6 @@ export const subtractDuration: {
|
|
|
934
934
|
mapEpochMillis(self, (millis) => millis - Duration.toMillis(Duration.fromInputUnsafe(duration)))
|
|
935
935
|
)
|
|
936
936
|
|
|
937
|
-
const addMillis = (date: Date, amount: number): void => {
|
|
938
|
-
date.setTime(date.getTime() + amount)
|
|
939
|
-
}
|
|
940
|
-
|
|
941
937
|
/** @internal */
|
|
942
938
|
export const add: {
|
|
943
939
|
(
|
|
@@ -949,20 +945,26 @@ export const add: {
|
|
|
949
945
|
): A
|
|
950
946
|
} = dual(
|
|
951
947
|
2,
|
|
952
|
-
(self: DateTime.DateTime, parts: Partial<DateTime.DateTime.PartsForMath>): DateTime.DateTime =>
|
|
953
|
-
|
|
948
|
+
(self: DateTime.DateTime, parts: Partial<DateTime.DateTime.PartsForMath>): DateTime.DateTime => {
|
|
949
|
+
// time units move the instant, calendar units move the wall clock
|
|
950
|
+
const shifted = mutateUtc(self, (date) => {
|
|
954
951
|
if (parts.milliseconds) {
|
|
955
|
-
|
|
952
|
+
date.setTime(date.getTime() + parts.milliseconds)
|
|
956
953
|
}
|
|
957
954
|
if (parts.seconds) {
|
|
958
|
-
|
|
955
|
+
date.setTime(date.getTime() + parts.seconds * 1000)
|
|
959
956
|
}
|
|
960
957
|
if (parts.minutes) {
|
|
961
|
-
|
|
958
|
+
date.setTime(date.getTime() + parts.minutes * 60 * 1000)
|
|
962
959
|
}
|
|
963
960
|
if (parts.hours) {
|
|
964
|
-
|
|
961
|
+
date.setTime(date.getTime() + parts.hours * 60 * 60 * 1000)
|
|
965
962
|
}
|
|
963
|
+
})
|
|
964
|
+
if (!parts.days && !parts.weeks && !parts.months && !parts.years) {
|
|
965
|
+
return shifted
|
|
966
|
+
}
|
|
967
|
+
return mutate(shifted, (date) => {
|
|
966
968
|
if (parts.days) {
|
|
967
969
|
date.setUTCDate(date.getUTCDate() + parts.days)
|
|
968
970
|
}
|
|
@@ -989,6 +991,7 @@ export const add: {
|
|
|
989
991
|
}
|
|
990
992
|
}
|
|
991
993
|
})
|
|
994
|
+
}
|
|
992
995
|
)
|
|
993
996
|
|
|
994
997
|
/** @internal */
|
package/src/internal/effect.ts
CHANGED
|
@@ -1507,13 +1507,19 @@ const succeedPayload = function(this: { readonly payload: any }, _value: unknown
|
|
|
1507
1507
|
// V8 includes the property name of a stored continuation in its stack trace.
|
|
1508
1508
|
// Other engines need an explicit frame for the stack cleaner to cut at.
|
|
1509
1509
|
const continuationMarksStack = (() => {
|
|
1510
|
+
const limit = getStackTraceLimit()
|
|
1511
|
+
if (limit === 0) return false
|
|
1510
1512
|
const marker = "~effect/Effect/stackProbe"
|
|
1511
1513
|
const probe = {
|
|
1512
1514
|
[marker]: function stackProbe() {
|
|
1513
|
-
return new Error()
|
|
1515
|
+
return new Error()
|
|
1514
1516
|
}
|
|
1515
1517
|
}
|
|
1516
|
-
|
|
1518
|
+
// Only the probe frame is needed to detect the continuation property name.
|
|
1519
|
+
setStackTraceLimit(1)
|
|
1520
|
+
const error = probe[marker]()
|
|
1521
|
+
setStackTraceLimit(limit)
|
|
1522
|
+
return error.stack?.includes("[as " + marker + "]") === true
|
|
1517
1523
|
})()
|
|
1518
1524
|
const mapCont = function(this: { readonly payload: any }, value: any, fiber: FiberImpl) {
|
|
1519
1525
|
const f = this.payload
|
|
@@ -4453,7 +4459,7 @@ export const cachedInvalidateWithTTL: {
|
|
|
4453
4459
|
const infiniteTTL = constant(Infinity)
|
|
4454
4460
|
|
|
4455
4461
|
interface CachedRun<A, E> {
|
|
4456
|
-
fiber: FiberImpl<A, E>
|
|
4462
|
+
readonly fiber: FiberImpl<A, E>
|
|
4457
4463
|
awaiters: number
|
|
4458
4464
|
}
|
|
4459
4465
|
|
|
@@ -4470,17 +4476,19 @@ const makeCachedUnsafe = <A, E, R>(
|
|
|
4470
4476
|
onExitUnsafe(fiber, () => {
|
|
4471
4477
|
// Abandon the run once every caller has left, unless it already finished.
|
|
4472
4478
|
if (--run.awaiters > 0 || current !== run) return
|
|
4473
|
-
// Detach
|
|
4474
|
-
// one that is being interrupted.
|
|
4479
|
+
// Detach before interruption so new callers start a fresh run.
|
|
4475
4480
|
current = undefined
|
|
4476
|
-
return fiberInterrupt(run.fiber
|
|
4481
|
+
return fiberInterrupt(run.fiber)
|
|
4477
4482
|
})
|
|
4478
|
-
return fiberJoin(run.fiber
|
|
4483
|
+
return fiberJoin(run.fiber)
|
|
4479
4484
|
}
|
|
4480
4485
|
|
|
4481
4486
|
return [
|
|
4482
4487
|
withFiber((fiber) => {
|
|
4483
|
-
if (current !== undefined)
|
|
4488
|
+
if (current !== undefined) {
|
|
4489
|
+
// A run joining itself is not an awaiter, so external callers can still abandon it.
|
|
4490
|
+
return fiber === current.fiber ? fiberJoin(current.fiber) : join(fiber, current)
|
|
4491
|
+
}
|
|
4484
4492
|
if (
|
|
4485
4493
|
exit !== undefined &&
|
|
4486
4494
|
(expiresAt === Infinity || fiber.getRef(ClockRef).currentTimeMillisUnsafe() < expiresAt)
|
|
@@ -4489,10 +4497,11 @@ const makeCachedUnsafe = <A, E, R>(
|
|
|
4489
4497
|
}
|
|
4490
4498
|
exit = undefined
|
|
4491
4499
|
const clock = fiber.getRef(ClockRef)
|
|
4492
|
-
const run: CachedRun<A, E> = { fiber:
|
|
4500
|
+
const run: CachedRun<A, E> = { fiber: new FiberImpl(fiber.context), awaiters: 0 }
|
|
4493
4501
|
current = run
|
|
4494
|
-
|
|
4495
|
-
|
|
4502
|
+
// Join before evaluating, which may synchronously re-enter and interrupt other awaiters.
|
|
4503
|
+
const joined = join(fiber, run)
|
|
4504
|
+
run.fiber.evaluate(
|
|
4496
4505
|
onExitPrimitive(self, (exit_) => {
|
|
4497
4506
|
// An abandoned run must not overwrite or clear a replacement run.
|
|
4498
4507
|
if (current !== run) return
|
|
@@ -4502,11 +4511,9 @@ const makeCachedUnsafe = <A, E, R>(
|
|
|
4502
4511
|
const duration = ttlMillis(exit_)
|
|
4503
4512
|
expiresAt = duration === Infinity ? Infinity : clock.currentTimeMillisUnsafe() + duration
|
|
4504
4513
|
exit = exit_
|
|
4505
|
-
})
|
|
4506
|
-
true,
|
|
4507
|
-
true
|
|
4514
|
+
}) as any
|
|
4508
4515
|
)
|
|
4509
|
-
return run.fiber._exit ??
|
|
4516
|
+
return run.fiber._exit ?? joined
|
|
4510
4517
|
}),
|
|
4511
4518
|
sync(() => {
|
|
4512
4519
|
exit = undefined
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { isReadonlyArrayNonEmpty, type NonEmptyReadonlyArray } from "../Array.ts"
|
|
2
|
+
import * as Context from "../Context.ts"
|
|
3
|
+
import * as Effect from "../Effect.ts"
|
|
4
|
+
import type * as GraphQL from "../graphql/GraphQL.ts"
|
|
5
|
+
import type { DocumentTemplate } from "../graphql/GraphQL.ts"
|
|
6
|
+
import type { PartialResult } from "../graphql/GraphQLClient.ts"
|
|
7
|
+
import {
|
|
8
|
+
DecodeError,
|
|
9
|
+
EncodeError,
|
|
10
|
+
GraphQLClientError,
|
|
11
|
+
type GraphQLError,
|
|
12
|
+
type Reason,
|
|
13
|
+
ResponseError
|
|
14
|
+
} from "../graphql/GraphQLClientError.ts"
|
|
15
|
+
import type { ExecutionResult, GraphQLRequest } from "../graphql/GraphQLProtocol.ts"
|
|
16
|
+
import * as Schema from "../Schema.ts"
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Builds a response error with raw data and transport metadata.
|
|
20
|
+
*
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
export const responseError = (
|
|
24
|
+
result: ExecutionResult | undefined,
|
|
25
|
+
errors: NonEmptyReadonlyArray<GraphQLError>
|
|
26
|
+
): ResponseError =>
|
|
27
|
+
new ResponseError({
|
|
28
|
+
errors,
|
|
29
|
+
...(result?.data === undefined ? {} : { data: result.data as Schema.Json }),
|
|
30
|
+
...(result?.extensions === undefined ? {} : { extensions: result.extensions }),
|
|
31
|
+
...(result?.status === undefined ? {} : { status: result.status }),
|
|
32
|
+
...(result?.headers === undefined ? {} : { headers: result.headers })
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Raw responses for partial results, used by resolvers to preserve error
|
|
37
|
+
* metadata. Mock client results have no entry.
|
|
38
|
+
*
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
export const partialResponses = new WeakMap<object, ExecutionResult>()
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Joins two printed pieces, adding a space only where two non-punctuators
|
|
45
|
+
* would otherwise touch. This is the generator printer's rule, so joining a
|
|
46
|
+
* generated template reproduces the printed document exactly.
|
|
47
|
+
*/
|
|
48
|
+
const concat = (left: string, right: string): string =>
|
|
49
|
+
/[\w"-]$/.test(left) && /^[\w"-]/.test(right) ? `${left} ${right}` : left + right
|
|
50
|
+
|
|
51
|
+
const concatAll = (pieces: ReadonlyArray<string>): string => pieces.reduce(concat, "")
|
|
52
|
+
|
|
53
|
+
/** Renders template parts, prefixing every name (the odd entries). */
|
|
54
|
+
const renderParts = (parts: DocumentTemplate.Parts, prefix: string): string =>
|
|
55
|
+
parts.map((part, i) => i % 2 === 1 ? prefix + part : part).join("")
|
|
56
|
+
|
|
57
|
+
const isShared = (fragment: DocumentTemplate.Fragment): boolean => fragment.body.length <= 1
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Renders the template once per prefix. The empty prefix renders it as
|
|
61
|
+
* written; any other prefix renames variables and per-slice fragments and
|
|
62
|
+
* aliases root fields to the prefixed response key.
|
|
63
|
+
*/
|
|
64
|
+
const render = (
|
|
65
|
+
kind: string,
|
|
66
|
+
name: string,
|
|
67
|
+
template: DocumentTemplate,
|
|
68
|
+
prefixes: ReadonlyArray<string>
|
|
69
|
+
): string =>
|
|
70
|
+
concatAll([
|
|
71
|
+
kind,
|
|
72
|
+
name,
|
|
73
|
+
template.variables.length === 0 ? "" : `(${
|
|
74
|
+
concatAll(
|
|
75
|
+
prefixes.flatMap((prefix) =>
|
|
76
|
+
template.variables.map((variable) => `$${prefix}${variable.name}:${variable.body}`)
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
})`,
|
|
80
|
+
template.directives === undefined ? "" : renderParts(template.directives, ""),
|
|
81
|
+
`{${
|
|
82
|
+
concatAll(prefixes.flatMap((prefix) =>
|
|
83
|
+
template.selections.map((selection) => {
|
|
84
|
+
const key = prefix === "" ? selection.alias : `${prefix}${selection.alias ?? selection.name}`
|
|
85
|
+
return `${key === undefined ? "" : `${key}:`}${selection.name ?? ""}${renderParts(selection.body, prefix)}`
|
|
86
|
+
})
|
|
87
|
+
))
|
|
88
|
+
}}`,
|
|
89
|
+
...template.fragments.flatMap((fragment) =>
|
|
90
|
+
(isShared(fragment) ? [""] : prefixes).map((prefix) =>
|
|
91
|
+
concatAll(["fragment", prefix + fragment.name, renderParts(fragment.body, prefix)])
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
])
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Joins a template into the document it was split from.
|
|
98
|
+
*
|
|
99
|
+
* @internal
|
|
100
|
+
*/
|
|
101
|
+
export const joinTemplate = (kind: string, name: string, template: DocumentTemplate): string =>
|
|
102
|
+
render(kind, name, template, [""])
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Why the template can't be sliced for any prefixes, if it can't: an operation
|
|
106
|
+
* directive references a variable, or a root selection is a fragment spread or
|
|
107
|
+
* inline fragment.
|
|
108
|
+
*
|
|
109
|
+
* @internal
|
|
110
|
+
*/
|
|
111
|
+
export const templateUnsliceableReason = (template: DocumentTemplate): string | undefined => {
|
|
112
|
+
if (template.directives !== undefined && template.directives.length > 1) {
|
|
113
|
+
return "its operation directives reference variables"
|
|
114
|
+
}
|
|
115
|
+
if (template.selections.some((selection) => selection.name === undefined)) {
|
|
116
|
+
return "it has a fragment spread or inline fragment at the root"
|
|
117
|
+
}
|
|
118
|
+
return undefined
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Renders one operation that repeats the template once per prefix. Each
|
|
123
|
+
* slice's variables, root response keys and per-slice fragments are renamed
|
|
124
|
+
* with its prefix; operation directives and shared fragments appear once.
|
|
125
|
+
* Prefixes must start a GraphQL name, and none may be a prefix of another.
|
|
126
|
+
*
|
|
127
|
+
* Throws rather than producing an invalid document when the template is
|
|
128
|
+
* unsliceable (see {@link templateUnsliceableReason}) or a renamed fragment
|
|
129
|
+
* would take a shared fragment's name.
|
|
130
|
+
*
|
|
131
|
+
* @internal
|
|
132
|
+
*/
|
|
133
|
+
export const renderSlices = (
|
|
134
|
+
kind: string,
|
|
135
|
+
name: string,
|
|
136
|
+
template: DocumentTemplate,
|
|
137
|
+
prefixes: NonEmptyReadonlyArray<string>
|
|
138
|
+
): string => {
|
|
139
|
+
const shared = new Set(template.fragments.filter(isShared).map((fragment) => fragment.name))
|
|
140
|
+
const collision = template.fragments
|
|
141
|
+
.flatMap((fragment) => isShared(fragment) ? [] : prefixes.map((prefix) => prefix + fragment.name))
|
|
142
|
+
.find((renamed) => shared.has(renamed))
|
|
143
|
+
const reason = templateUnsliceableReason(template) ??
|
|
144
|
+
(collision === undefined ? undefined : `fragment ${collision} would collide with a shared fragment`)
|
|
145
|
+
if (reason !== undefined) throw new Error(`Cannot render slices of operation ${name}: ${reason}`)
|
|
146
|
+
return render(kind, name, template, prefixes)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Forces POST for alias batches to avoid GET URL length limits.
|
|
151
|
+
*
|
|
152
|
+
* @internal
|
|
153
|
+
*/
|
|
154
|
+
export const ForcePost = Context.Reference<boolean>("effect/graphql/ForcePost", { defaultValue: () => false })
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* JSON with object keys sorted, so equal JSON values give equal strings.
|
|
158
|
+
*
|
|
159
|
+
* @internal
|
|
160
|
+
*/
|
|
161
|
+
export const canonicalJson = (value: unknown): string =>
|
|
162
|
+
JSON.stringify(value, (_, value) =>
|
|
163
|
+
value !== null && typeof value === "object" && !Array.isArray(value)
|
|
164
|
+
? Object.fromEntries(Object.keys(value).sort().map((key) => [key, value[key]]))
|
|
165
|
+
: value)
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Shared variable encoding, result decoding and client error mapping.
|
|
169
|
+
*
|
|
170
|
+
* @internal
|
|
171
|
+
*/
|
|
172
|
+
export const makeCodec = <Op extends GraphQL.Any>(operation: Op) => {
|
|
173
|
+
const fail = (reason: Reason) => new GraphQLClientError({ operation: operation.name, reason })
|
|
174
|
+
const schemaFail = (make: (description: string) => Reason) => (error: Schema.SchemaError) =>
|
|
175
|
+
Effect.fail(fail(make(error.message)))
|
|
176
|
+
const encode = Schema.encodeEffect(operation.variables)
|
|
177
|
+
const decode = Schema.decodeUnknownEffect(operation.result)
|
|
178
|
+
|
|
179
|
+
const encodeVariables = (
|
|
180
|
+
variables: GraphQL.Variables<Op> | undefined
|
|
181
|
+
): Effect.Effect<unknown, GraphQLClientError, Op["variables"]["EncodingServices"]> =>
|
|
182
|
+
Effect.catch(encode(variables ?? {}), schemaFail((description) => new EncodeError({ description })))
|
|
183
|
+
|
|
184
|
+
const decodeData = (
|
|
185
|
+
data: unknown
|
|
186
|
+
): Effect.Effect<GraphQL.Result<Op>, GraphQLClientError, Op["result"]["DecodingServices"]> =>
|
|
187
|
+
Effect.catch(decode(data), schemaFail((description) => new DecodeError({ description })))
|
|
188
|
+
|
|
189
|
+
// GraphQL requires errors when data is null or missing. Check before decoding,
|
|
190
|
+
// since schemas such as Schema.Json accept null.
|
|
191
|
+
const failResponse = (result: ExecutionResult): Effect.Effect<never, GraphQLClientError> => {
|
|
192
|
+
const errors = result.errors ?? []
|
|
193
|
+
return Effect.fail(fail(
|
|
194
|
+
isReadonlyArrayNonEmpty(errors)
|
|
195
|
+
? responseError(result, errors)
|
|
196
|
+
: new DecodeError({ description: "data is null or missing without errors" })
|
|
197
|
+
))
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const decodeStrict = (
|
|
201
|
+
result: ExecutionResult
|
|
202
|
+
): Effect.Effect<GraphQL.Result<Op>, GraphQLClientError, Op["result"]["DecodingServices"]> =>
|
|
203
|
+
isReadonlyArrayNonEmpty(result.errors ?? []) || result.data === null || result.data === undefined
|
|
204
|
+
? failResponse(result)
|
|
205
|
+
: decodeData(result.data)
|
|
206
|
+
|
|
207
|
+
const decodePartial = (
|
|
208
|
+
result: ExecutionResult
|
|
209
|
+
): Effect.Effect<PartialResult<GraphQL.Result<Op>>, GraphQLClientError, Op["result"]["DecodingServices"]> => {
|
|
210
|
+
if (result.data === null || result.data === undefined) return failResponse(result)
|
|
211
|
+
return Effect.map(decodeData(result.data), (data): PartialResult<GraphQL.Result<Op>> => {
|
|
212
|
+
const partial = { data, errors: result.errors ?? [] }
|
|
213
|
+
partialResponses.set(partial, result)
|
|
214
|
+
return partial
|
|
215
|
+
})
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return { fail, schemaFail, encodeVariables, failResponse, decodeStrict, decodePartial } as const
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Each real client method's runner for batches: its middleware and protocol,
|
|
223
|
+
* sending as POST. Mock and custom methods have none.
|
|
224
|
+
*
|
|
225
|
+
* @internal
|
|
226
|
+
*/
|
|
227
|
+
export const rawExecutors = new WeakMap<
|
|
228
|
+
object,
|
|
229
|
+
(request: GraphQLRequest) => Effect.Effect<ExecutionResult, unknown, unknown>
|
|
230
|
+
>()
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Splits a batched response, removing prefixes from root keys and error paths.
|
|
234
|
+
* Returns undefined if an error matches no slice or data is null or missing.
|
|
235
|
+
*
|
|
236
|
+
* @internal
|
|
237
|
+
*/
|
|
238
|
+
export const splitSlices = (
|
|
239
|
+
result: ExecutionResult,
|
|
240
|
+
template: DocumentTemplate,
|
|
241
|
+
prefixes: ReadonlyArray<string>
|
|
242
|
+
): ReadonlyArray<ExecutionResult> | undefined => {
|
|
243
|
+
const sliceErrors = prefixes.map((): Array<GraphQLError> => [])
|
|
244
|
+
for (const error of result.errors ?? []) {
|
|
245
|
+
const key = error.path?.[0]
|
|
246
|
+
// No prefix is a prefix of another, so at most one matches.
|
|
247
|
+
const index = typeof key === "string" ? prefixes.findIndex((prefix) => key.startsWith(prefix)) : -1
|
|
248
|
+
if (index === -1) return undefined
|
|
249
|
+
sliceErrors[index].push(
|
|
250
|
+
{ ...error, path: [(key as string).slice(prefixes[index].length), ...error.path!.slice(1)] } as GraphQLError
|
|
251
|
+
)
|
|
252
|
+
}
|
|
253
|
+
if (result.data === null || result.data === undefined) return undefined
|
|
254
|
+
const data = result.data as Record<string, unknown>
|
|
255
|
+
return prefixes.map((prefix, i) => {
|
|
256
|
+
const sliceData: Record<string, unknown> = {}
|
|
257
|
+
for (const selection of template.selections) {
|
|
258
|
+
const key = (selection.alias ?? selection.name)!
|
|
259
|
+
if (Object.hasOwn(data, prefix + key)) sliceData[key] = data[prefix + key]
|
|
260
|
+
}
|
|
261
|
+
return { ...result, data: sliceData, errors: sliceErrors[i] }
|
|
262
|
+
})
|
|
263
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as Headers from "../http/Headers.ts"
|
|
2
|
+
import * as Schema from "../Schema.ts"
|
|
3
|
+
import * as SchemaGetter from "../SchemaGetter.ts"
|
|
4
|
+
|
|
5
|
+
// Keep headers branded at runtime while encoding only their string entries.
|
|
6
|
+
export const HeadersSchema = Schema.Record(Schema.String, Schema.String).pipe(
|
|
7
|
+
Schema.decodeTo(Schema.declare<Headers.Headers>(Headers.isHeaders), {
|
|
8
|
+
decode: SchemaGetter.transform(Headers.fromInput),
|
|
9
|
+
encode: SchemaGetter.transform((headers) => ({ ...headers }))
|
|
10
|
+
})
|
|
11
|
+
)
|
package/src/internal/request.ts
CHANGED
|
@@ -4,6 +4,8 @@ import type { Effect } from "../Effect.ts"
|
|
|
4
4
|
import type { Exit } from "../Exit.ts"
|
|
5
5
|
import type { Fiber } from "../Fiber.ts"
|
|
6
6
|
import { dual } from "../Function.ts"
|
|
7
|
+
import * as MutableHashMap from "../MutableHashMap.ts"
|
|
8
|
+
import * as Option from "../Option.ts"
|
|
7
9
|
import type * as Request from "../Request.ts"
|
|
8
10
|
import { makeEntry } from "../Request.ts"
|
|
9
11
|
import type { RequestResolver } from "../RequestResolver.ts"
|
|
@@ -67,10 +69,36 @@ export const requestUnsafe = <A extends Request.Any>(
|
|
|
67
69
|
return () => removeEntryUnsafe(options.resolver, entry)
|
|
68
70
|
}
|
|
69
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Pending batches of resolvers whose `batchKey` is in this set match keys with
|
|
74
|
+
* `Equal` instead of by reference.
|
|
75
|
+
*
|
|
76
|
+
* @internal
|
|
77
|
+
*/
|
|
78
|
+
export const equalBatchKeys = new WeakSet<Function>()
|
|
79
|
+
|
|
80
|
+
interface BatchMap {
|
|
81
|
+
get(key: unknown): Batch | undefined
|
|
82
|
+
has(key: unknown): boolean
|
|
83
|
+
set(key: unknown, batch: Batch): void
|
|
84
|
+
delete(key: unknown): void
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const makeBatchMap = (resolver: RequestResolver<any>): BatchMap => {
|
|
88
|
+
if (!equalBatchKeys.has(resolver.batchKey)) return new Map()
|
|
89
|
+
const map = MutableHashMap.empty<unknown, Batch>()
|
|
90
|
+
return {
|
|
91
|
+
get: (key) => Option.getOrUndefined(MutableHashMap.get(map, key)),
|
|
92
|
+
has: (key) => MutableHashMap.has(map, key),
|
|
93
|
+
set: (key, batch) => MutableHashMap.set(map, key, batch),
|
|
94
|
+
delete: (key) => MutableHashMap.remove(map, key)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
70
98
|
interface Batch {
|
|
71
99
|
key: unknown
|
|
72
100
|
resolver: RequestResolver<any>
|
|
73
|
-
map:
|
|
101
|
+
map: BatchMap
|
|
74
102
|
readonly entrySet: Set<Request.Entry<any>>
|
|
75
103
|
readonly entries: Set<Request.Entry<any>>
|
|
76
104
|
readonly delayEffect: Effect<void>
|
|
@@ -79,7 +107,7 @@ interface Batch {
|
|
|
79
107
|
}
|
|
80
108
|
|
|
81
109
|
const batchPool: Array<Batch> = []
|
|
82
|
-
const pendingBatches = new WeakMap<RequestResolver<any>,
|
|
110
|
+
const pendingBatches = new WeakMap<RequestResolver<any>, BatchMap>()
|
|
83
111
|
|
|
84
112
|
const addEntry = <A extends Request.Any>(
|
|
85
113
|
resolver: RequestResolver<A>,
|
|
@@ -93,7 +121,7 @@ const addEntry = <A extends Request.Any>(
|
|
|
93
121
|
) => {
|
|
94
122
|
let batchMap = pendingBatches.get(resolver)
|
|
95
123
|
if (!batchMap) {
|
|
96
|
-
batchMap =
|
|
124
|
+
batchMap = makeBatchMap(resolver)
|
|
97
125
|
pendingBatches.set(resolver, batchMap)
|
|
98
126
|
}
|
|
99
127
|
let batch: Batch | undefined
|
|
@@ -48,6 +48,8 @@ function renderEmittableAnnotation(input: unknown): string | undefined {
|
|
|
48
48
|
return entries.length === 0 ? "{}" : `{ ${entries.join(", ")} }`
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
const canonicalFiniteCheck = `Schema.isFinite().annotate({ "expected": "a finite number" })`
|
|
52
|
+
|
|
51
53
|
function renderAnnotations(
|
|
52
54
|
annotations: Schema.Annotations.Annotations | undefined
|
|
53
55
|
): string | undefined {
|
|
@@ -341,7 +343,11 @@ export function toCodeDocument(
|
|
|
341
343
|
let runtime = base.runtime + runtimeAnnotate(representation.annotations)
|
|
342
344
|
for (let index = 0; index < representation.checks.length; index++) {
|
|
343
345
|
const check = representation.checks[index]
|
|
344
|
-
|
|
346
|
+
const compiledCheck = compileCheck(check, [...path, "checks", index])
|
|
347
|
+
// Only collapse a bare number's leading canonical check.
|
|
348
|
+
runtime = runtime === "Schema.Number" && compiledCheck === canonicalFiniteCheck
|
|
349
|
+
? "Schema.Finite"
|
|
350
|
+
: `${runtime}.check(${compiledCheck})`
|
|
345
351
|
}
|
|
346
352
|
return makeCode(runtime, base.Type)
|
|
347
353
|
}
|
|
@@ -121,6 +121,37 @@ function hasNoCollisions(left: JsonSchema.JsonSchema, rightKeys: ReadonlyArray<s
|
|
|
121
121
|
return typeof left.$ref !== "string" && rightKeys.every((key) => !Object.hasOwn(left, key))
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
// Every bound on one schema object applies, so a repeated bound reduces to its tighter value.
|
|
125
|
+
const lowerBoundKeywords = "|minimum|exclusiveMinimum|minLength|minItems|minProperties|"
|
|
126
|
+
const upperBoundKeywords = "|maximum|exclusiveMaximum|maxLength|maxItems|maxProperties|"
|
|
127
|
+
|
|
128
|
+
// Tightens repeated bounds and drops an inclusive or exclusive bound implied by the other on the same side. Returns
|
|
129
|
+
// `undefined` for a `$ref` schema or a non-bound collision, so the caller falls back to `allOf`.
|
|
130
|
+
function mergeInlineCheck(
|
|
131
|
+
left: JsonSchema.JsonSchema,
|
|
132
|
+
right: JsonSchema.JsonSchema,
|
|
133
|
+
rightKeys: ReadonlyArray<string>
|
|
134
|
+
): JsonSchema.JsonSchema | undefined {
|
|
135
|
+
if (typeof left.$ref === "string") return undefined
|
|
136
|
+
const out: JsonSchema.JsonSchema = { ...left, ...right }
|
|
137
|
+
for (const key of rightKeys) {
|
|
138
|
+
if (!Object.hasOwn(left, key)) continue
|
|
139
|
+
const a = left[key]
|
|
140
|
+
const b = right[key]
|
|
141
|
+
if (typeof a !== "number" || typeof b !== "number") return undefined
|
|
142
|
+
if (lowerBoundKeywords.includes(`|${key}|`)) out[key] = Math.max(a, b)
|
|
143
|
+
else if (upperBoundKeywords.includes(`|${key}|`)) out[key] = Math.min(a, b)
|
|
144
|
+
else return undefined
|
|
145
|
+
}
|
|
146
|
+
if (typeof out.minimum === "number" && typeof out.exclusiveMinimum === "number") {
|
|
147
|
+
delete out[out.exclusiveMinimum >= out.minimum ? "minimum" : "exclusiveMinimum"]
|
|
148
|
+
}
|
|
149
|
+
if (typeof out.maximum === "number" && typeof out.exclusiveMaximum === "number") {
|
|
150
|
+
delete out[out.exclusiveMaximum <= out.maximum ? "maximum" : "exclusiveMaximum"]
|
|
151
|
+
}
|
|
152
|
+
return out
|
|
153
|
+
}
|
|
154
|
+
|
|
124
155
|
// `format` and `content*` can affect validation, so they are not treated as pure annotations.
|
|
125
156
|
const promotableAnnotationKeywords = "|title|description|default|examples|readOnly|writeOnly|"
|
|
126
157
|
const inlineableAnnotatedCheckKeywords = inlineableCheckKeywords + promotableAnnotationKeywords
|
|
@@ -149,8 +180,9 @@ function appendJsonSchema(
|
|
|
149
180
|
: appendJsonSchema(base, extracted.schema, inlineCheck)
|
|
150
181
|
}
|
|
151
182
|
}
|
|
152
|
-
if (inlineCheck
|
|
153
|
-
|
|
183
|
+
if (inlineCheck) {
|
|
184
|
+
const merged = mergeInlineCheck(left, right, rightKeys)
|
|
185
|
+
if (merged !== undefined) return merged
|
|
154
186
|
}
|
|
155
187
|
const members = Array.isArray(right.allOf) && rightKeys.length === 1 ? right.allOf : [right]
|
|
156
188
|
if (Array.isArray(left.allOf)) {
|
package/src/internal/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** @internal */
|
|
2
|
-
export const version = "4.0.
|
|
2
|
+
export const version = "4.0.4"
|