effect 4.1.0 → 4.1.2
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/README.md +30 -0
- package/THIRD_PARTY_NOTICES.md +62 -0
- package/ai-docs/package.json +2 -2
- package/dist/BigDecimal.d.ts +139 -7
- package/dist/BigDecimal.d.ts.map +1 -1
- package/dist/BigDecimal.js +83 -14
- package/dist/BigDecimal.js.map +1 -1
- package/dist/ByteSize.d.ts.map +1 -1
- package/dist/ByteSize.js +27 -14
- package/dist/ByteSize.js.map +1 -1
- package/dist/Equal.d.ts +2 -2
- package/dist/Equal.d.ts.map +1 -1
- package/dist/Equal.js +3 -3
- package/dist/Equal.js.map +1 -1
- package/dist/Hash.d.ts +3 -2
- package/dist/Hash.d.ts.map +1 -1
- package/dist/Hash.js +5 -4
- package/dist/Hash.js.map +1 -1
- package/dist/Iterable.d.ts.map +1 -1
- package/dist/Iterable.js +38 -32
- package/dist/Iterable.js.map +1 -1
- package/dist/JsonSchema.d.ts.map +1 -1
- package/dist/JsonSchema.js +27 -6
- package/dist/JsonSchema.js.map +1 -1
- package/dist/MutableRef.d.ts.map +1 -1
- package/dist/MutableRef.js +0 -7
- package/dist/MutableRef.js.map +1 -1
- package/dist/Path.d.ts.map +1 -1
- package/dist/Path.js +5 -1
- package/dist/Path.js.map +1 -1
- package/dist/Pool.d.ts.map +1 -1
- package/dist/Pool.js +2 -1
- package/dist/Pool.js.map +1 -1
- package/dist/Ref.d.ts.map +1 -1
- package/dist/Ref.js +0 -8
- package/dist/Ref.js.map +1 -1
- package/dist/Schedule.d.ts.map +1 -1
- package/dist/Schedule.js +8 -3
- package/dist/Schedule.js.map +1 -1
- package/dist/Schema.d.ts +2 -1
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +2 -1
- package/dist/Schema.js.map +1 -1
- package/dist/SchemaRepresentation.d.ts +4 -2
- package/dist/SchemaRepresentation.d.ts.map +1 -1
- package/dist/SchemaRepresentation.js +4 -2
- package/dist/SchemaRepresentation.js.map +1 -1
- package/dist/SchemaTransformation.d.ts +2 -2
- package/dist/SchemaTransformation.js +2 -2
- package/dist/Stream.d.ts.map +1 -1
- package/dist/Stream.js +6 -5
- package/dist/Stream.js.map +1 -1
- package/dist/ai/McpClient.d.ts +171 -19
- package/dist/ai/McpClient.d.ts.map +1 -1
- package/dist/ai/McpClient.js +277 -66
- package/dist/ai/McpClient.js.map +1 -1
- package/dist/ai/McpSchema.d.ts +108 -0
- package/dist/ai/McpSchema.d.ts.map +1 -1
- package/dist/ai/McpSchema.js +99 -0
- package/dist/ai/McpSchema.js.map +1 -1
- package/dist/ai/McpServer.d.ts +120 -6
- package/dist/ai/McpServer.d.ts.map +1 -1
- package/dist/ai/McpServer.js +258 -49
- package/dist/ai/McpServer.js.map +1 -1
- package/dist/ai/Prompt.d.ts.map +1 -1
- package/dist/ai/Prompt.js +20 -11
- package/dist/ai/Prompt.js.map +1 -1
- package/dist/ai/Tool.d.ts.map +1 -1
- package/dist/ai/Tool.js +5 -7
- package/dist/ai/Tool.js.map +1 -1
- package/dist/ai/internal/mcpCore.js +72 -3
- package/dist/ai/internal/mcpCore.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2024_11_05.js +3 -1
- package/dist/ai/internal/mcpProtocol/v2024_11_05.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2025_03_26.js +3 -1
- package/dist/ai/internal/mcpProtocol/v2025_03_26.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2025_06_18.js +3 -1
- package/dist/ai/internal/mcpProtocol/v2025_06_18.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2025_11_25.js +3 -1
- package/dist/ai/internal/mcpProtocol/v2025_11_25.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2026_07_28.js +44 -8
- package/dist/ai/internal/mcpProtocol/v2026_07_28.js.map +1 -1
- package/dist/ai/internal/mcpProtocol.js +12 -0
- package/dist/ai/internal/mcpProtocol.js.map +1 -1
- package/dist/ai/internal/mcpRuntime.js +3 -3
- package/dist/ai/internal/mcpRuntime.js.map +1 -1
- package/dist/ai/internal/mcpSkills.d.ts +2 -0
- package/dist/ai/internal/mcpSkills.d.ts.map +1 -0
- package/dist/ai/internal/mcpSkills.js +428 -0
- package/dist/ai/internal/mcpSkills.js.map +1 -0
- package/dist/ai/internal/structured-output.js +11 -2
- package/dist/ai/internal/structured-output.js.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.js +30 -11
- package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
- package/dist/cluster/Entity.d.ts +26 -0
- package/dist/cluster/Entity.d.ts.map +1 -1
- package/dist/cluster/Entity.js.map +1 -1
- package/dist/cluster/MessageStorage.d.ts +6 -6
- package/dist/cluster/MessageStorage.d.ts.map +1 -1
- package/dist/cluster/MessageStorage.js +1 -3
- package/dist/cluster/MessageStorage.js.map +1 -1
- package/dist/cluster/Reply.d.ts +1 -1
- package/dist/cluster/Reply.d.ts.map +1 -1
- package/dist/cluster/Reply.js.map +1 -1
- package/dist/cluster/Runners.d.ts.map +1 -1
- package/dist/cluster/Runners.js +13 -2
- package/dist/cluster/Runners.js.map +1 -1
- package/dist/cluster/Sharding.d.ts +13 -0
- package/dist/cluster/Sharding.d.ts.map +1 -1
- package/dist/cluster/Sharding.js +4 -1
- package/dist/cluster/Sharding.js.map +1 -1
- package/dist/cluster/internal/clusterAbandon.d.ts.map +1 -1
- package/dist/cluster/internal/clusterAbandon.js +6 -4
- package/dist/cluster/internal/clusterAbandon.js.map +1 -1
- package/dist/cluster/internal/entityManager.js +63 -11
- package/dist/cluster/internal/entityManager.js.map +1 -1
- package/dist/cluster/internal/transactionNotifications.d.ts +5 -0
- package/dist/cluster/internal/transactionNotifications.d.ts.map +1 -0
- package/dist/cluster/internal/transactionNotifications.js +5 -0
- package/dist/cluster/internal/transactionNotifications.js.map +1 -0
- package/dist/crypto/Aead.d.ts +2 -1
- package/dist/crypto/Aead.d.ts.map +1 -1
- package/dist/crypto/Aead.js +2 -2
- package/dist/crypto/Aead.js.map +1 -1
- package/dist/crypto/Cipher.d.ts +2 -1
- package/dist/crypto/Cipher.d.ts.map +1 -1
- package/dist/crypto/Cipher.js +2 -2
- package/dist/crypto/Cipher.js.map +1 -1
- package/dist/crypto/KeyAgreement.d.ts +3 -2
- package/dist/crypto/KeyAgreement.d.ts.map +1 -1
- package/dist/crypto/KeyAgreement.js +2 -2
- package/dist/crypto/KeyAgreement.js.map +1 -1
- package/dist/crypto/KeyFormat.d.ts +33 -1
- package/dist/crypto/KeyFormat.d.ts.map +1 -1
- package/dist/crypto/KeyFormat.js.map +1 -1
- package/dist/crypto/KeyWrap.d.ts +4 -3
- package/dist/crypto/KeyWrap.d.ts.map +1 -1
- package/dist/crypto/KeyWrap.js +2 -2
- package/dist/crypto/KeyWrap.js.map +1 -1
- package/dist/crypto/Mac.d.ts +2 -1
- package/dist/crypto/Mac.d.ts.map +1 -1
- package/dist/crypto/Mac.js +2 -2
- package/dist/crypto/Mac.js.map +1 -1
- package/dist/crypto/Signature.d.ts +3 -2
- package/dist/crypto/Signature.d.ts.map +1 -1
- package/dist/crypto/Signature.js +2 -2
- package/dist/crypto/Signature.js.map +1 -1
- package/dist/crypto/WebCrypto.d.ts +19 -0
- package/dist/crypto/WebCrypto.d.ts.map +1 -1
- package/dist/crypto/WebCrypto.js.map +1 -1
- package/dist/crypto/internal/asymmetric.js.map +1 -1
- package/dist/crypto/internal/key.js +3 -2
- package/dist/crypto/internal/key.js.map +1 -1
- package/dist/encoding/Base64Url.d.ts.map +1 -1
- package/dist/encoding/Base64Url.js +26 -3
- package/dist/encoding/Base64Url.js.map +1 -1
- package/dist/encoding/Json5.d.ts +44 -0
- package/dist/encoding/Json5.d.ts.map +1 -0
- package/dist/encoding/Json5.js +56 -0
- package/dist/encoding/Json5.js.map +1 -0
- package/dist/encoding/Jsonc.d.ts +47 -0
- package/dist/encoding/Jsonc.d.ts.map +1 -0
- package/dist/encoding/Jsonc.js +120 -0
- package/dist/encoding/Jsonc.js.map +1 -0
- package/dist/encoding/Ndjson.d.ts +5 -4
- package/dist/encoding/Ndjson.d.ts.map +1 -1
- package/dist/encoding/Ndjson.js +6 -5
- package/dist/encoding/Ndjson.js.map +1 -1
- package/dist/encoding/SchemaBinary.d.ts +94 -0
- package/dist/encoding/SchemaBinary.d.ts.map +1 -1
- package/dist/encoding/SchemaBinary.js +219 -6
- package/dist/encoding/SchemaBinary.js.map +1 -1
- package/dist/encoding/Sse.d.ts +3 -1
- package/dist/encoding/Sse.d.ts.map +1 -1
- package/dist/encoding/Sse.js +5 -3
- package/dist/encoding/Sse.js.map +1 -1
- package/dist/encoding/index.d.ts +10 -0
- package/dist/encoding/index.d.ts.map +1 -1
- package/dist/encoding/index.js +10 -0
- package/dist/encoding/index.js.map +1 -1
- package/dist/eventlog/EventLog.d.ts +7 -0
- package/dist/eventlog/EventLog.d.ts.map +1 -1
- package/dist/eventlog/EventLog.js +7 -0
- package/dist/eventlog/EventLog.js.map +1 -1
- package/dist/eventlog/EventLogServer.d.ts +7 -1
- package/dist/eventlog/EventLogServer.d.ts.map +1 -1
- package/dist/eventlog/EventLogServer.js +55 -24
- package/dist/eventlog/EventLogServer.js.map +1 -1
- package/dist/eventlog/EventLogServerEncrypted.d.ts +10 -0
- package/dist/eventlog/EventLogServerEncrypted.d.ts.map +1 -1
- package/dist/eventlog/EventLogServerEncrypted.js.map +1 -1
- package/dist/eventlog/EventLogServerUnencrypted.d.ts +17 -0
- package/dist/eventlog/EventLogServerUnencrypted.d.ts.map +1 -1
- package/dist/eventlog/EventLogServerUnencrypted.js +14 -2
- package/dist/eventlog/EventLogServerUnencrypted.js.map +1 -1
- package/dist/eventlog/EventLogSessionAuth.d.ts +21 -0
- package/dist/eventlog/EventLogSessionAuth.d.ts.map +1 -1
- package/dist/eventlog/EventLogSessionAuth.js +22 -0
- package/dist/eventlog/EventLogSessionAuth.js.map +1 -1
- package/dist/graphql/GraphQLClient.d.ts +3 -1
- package/dist/graphql/GraphQLClient.d.ts.map +1 -1
- package/dist/graphql/GraphQLClient.js.map +1 -1
- package/dist/graphql/GraphQLClientError.d.ts +14 -9
- package/dist/graphql/GraphQLClientError.d.ts.map +1 -1
- package/dist/graphql/GraphQLClientError.js +14 -21
- package/dist/graphql/GraphQLClientError.js.map +1 -1
- package/dist/graphql/GraphQLProtocol.d.ts +12 -3
- package/dist/graphql/GraphQLProtocol.d.ts.map +1 -1
- package/dist/graphql/GraphQLProtocol.js +4 -1
- package/dist/graphql/GraphQLProtocol.js.map +1 -1
- package/dist/http/HttpClient.d.ts +204 -16
- package/dist/http/HttpClient.d.ts.map +1 -1
- package/dist/http/HttpClient.js +93 -13
- package/dist/http/HttpClient.js.map +1 -1
- package/dist/http/HttpServerRequest.d.ts.map +1 -1
- package/dist/http/HttpServerRequest.js +38 -22
- package/dist/http/HttpServerRequest.js.map +1 -1
- package/dist/http/internal/mimeTypes.d.ts +4 -1
- package/dist/http/internal/mimeTypes.d.ts.map +1 -1
- package/dist/http/internal/mimeTypes.js +4 -1
- package/dist/http/internal/mimeTypes.js.map +1 -1
- package/dist/http-api/HttpApiSchema.js +1 -1
- package/dist/http-api/HttpApiSchema.js.map +1 -1
- package/dist/internal/dateTime.js +66 -27
- package/dist/internal/dateTime.js.map +1 -1
- package/dist/internal/effect.js +10 -0
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/glob.js +234 -56
- package/dist/internal/glob.js.map +1 -1
- package/dist/internal/graphql.js +21 -7
- package/dist/internal/graphql.js.map +1 -1
- package/dist/internal/graphqlHeaders.d.ts +7 -0
- package/dist/internal/graphqlHeaders.d.ts.map +1 -1
- package/dist/internal/graphqlHeaders.js +11 -0
- package/dist/internal/graphqlHeaders.js.map +1 -1
- package/dist/internal/jsonParser.d.ts +5 -0
- package/dist/internal/jsonParser.d.ts.map +1 -0
- package/dist/internal/jsonParser.js +280 -0
- package/dist/internal/jsonParser.js.map +1 -0
- package/dist/internal/persistence.js +8 -1
- package/dist/internal/persistence.js.map +1 -1
- package/dist/internal/request.js +29 -42
- package/dist/internal/request.js.map +1 -1
- package/dist/internal/schema/fromJsonSchemaDocument.js +7 -8
- package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
- package/dist/internal/sql.js +16 -0
- package/dist/internal/sql.js.map +1 -1
- package/dist/internal/version.js +1 -1
- package/dist/jose/JoseError.d.ts +285 -0
- package/dist/jose/JoseError.d.ts.map +1 -0
- package/dist/jose/JoseError.js +269 -0
- package/dist/jose/JoseError.js.map +1 -0
- package/dist/jose/Jwe.d.ts +128 -0
- package/dist/jose/Jwe.d.ts.map +1 -0
- package/dist/jose/Jwe.js +134 -0
- package/dist/jose/Jwe.js.map +1 -0
- package/dist/jose/Jwk.d.ts +597 -0
- package/dist/jose/Jwk.d.ts.map +1 -0
- package/dist/jose/Jwk.js +503 -0
- package/dist/jose/Jwk.js.map +1 -0
- package/dist/jose/Jwks.d.ts +236 -0
- package/dist/jose/Jwks.d.ts.map +1 -0
- package/dist/jose/Jwks.js +306 -0
- package/dist/jose/Jwks.js.map +1 -0
- package/dist/jose/Jws.d.ts +177 -0
- package/dist/jose/Jws.d.ts.map +1 -0
- package/dist/jose/Jws.js +183 -0
- package/dist/jose/Jws.js.map +1 -0
- package/dist/jose/Jwt.d.ts +270 -0
- package/dist/jose/Jwt.d.ts.map +1 -0
- package/dist/jose/Jwt.js +293 -0
- package/dist/jose/Jwt.js.map +1 -0
- package/dist/jose/index.d.ts +51 -0
- package/dist/jose/index.d.ts.map +1 -0
- package/dist/jose/index.js +52 -0
- package/dist/jose/index.js.map +1 -0
- package/dist/jose/internal/compact.d.ts +2 -0
- package/dist/jose/internal/compact.d.ts.map +1 -0
- package/dist/jose/internal/compact.js +179 -0
- package/dist/jose/internal/compact.js.map +1 -0
- package/dist/net/Host.d.ts.map +1 -1
- package/dist/net/Host.js +5 -10
- package/dist/net/Host.js.map +1 -1
- package/dist/observability/OtlpExporter.d.ts +4 -0
- package/dist/observability/OtlpExporter.d.ts.map +1 -1
- package/dist/observability/OtlpExporter.js +40 -12
- package/dist/observability/OtlpExporter.js.map +1 -1
- package/dist/observability/OtlpSerialization.d.ts +1 -1
- package/dist/observability/OtlpSerialization.d.ts.map +1 -1
- package/dist/observability/OtlpSerialization.js +10 -4
- package/dist/observability/OtlpSerialization.js.map +1 -1
- package/dist/observability/internal/otlpProtobuf.js +3 -3
- package/dist/observability/internal/otlpProtobuf.js.map +1 -1
- package/dist/observability/internal/protobuf.js +6 -0
- package/dist/observability/internal/protobuf.js.map +1 -1
- package/dist/persistence/CircuitBreaker.d.ts +98 -38
- package/dist/persistence/CircuitBreaker.d.ts.map +1 -1
- package/dist/persistence/CircuitBreaker.js +67 -29
- package/dist/persistence/CircuitBreaker.js.map +1 -1
- package/dist/persistence/RateLimiter.d.ts +15 -0
- package/dist/persistence/RateLimiter.d.ts.map +1 -1
- package/dist/persistence/RateLimiter.js +76 -16
- package/dist/persistence/RateLimiter.js.map +1 -1
- package/dist/persistence/index.d.ts +1 -1
- package/dist/persistence/index.js +1 -1
- package/dist/reactivity/AtomRegistry.js +17 -7
- package/dist/reactivity/AtomRegistry.js.map +1 -1
- package/dist/rpc/Rpc.d.ts +1 -1
- package/dist/rpc/Rpc.d.ts.map +1 -1
- package/dist/rpc/Rpc.js.map +1 -1
- package/dist/rpc/RpcClient.d.ts +14 -2
- package/dist/rpc/RpcClient.d.ts.map +1 -1
- package/dist/rpc/RpcClient.js +38 -21
- package/dist/rpc/RpcClient.js.map +1 -1
- package/dist/rpc/RpcMessage.d.ts +3 -2
- package/dist/rpc/RpcMessage.d.ts.map +1 -1
- package/dist/rpc/RpcMessage.js.map +1 -1
- package/dist/rpc/RpcServer.d.ts.map +1 -1
- package/dist/rpc/RpcServer.js +10 -1
- package/dist/rpc/RpcServer.js.map +1 -1
- package/dist/sql/Migrator.d.ts +9 -1
- package/dist/sql/Migrator.d.ts.map +1 -1
- package/dist/sql/Migrator.js +18 -6
- package/dist/sql/Migrator.js.map +1 -1
- package/dist/sql/SqlClient.d.ts +46 -3
- package/dist/sql/SqlClient.d.ts.map +1 -1
- package/dist/sql/SqlClient.js +40 -15
- package/dist/sql/SqlClient.js.map +1 -1
- package/dist/sql/Statement.d.ts +46 -3
- package/dist/sql/Statement.d.ts.map +1 -1
- package/dist/sql/Statement.js +32 -26
- package/dist/sql/Statement.js.map +1 -1
- package/dist/workflow/Workflow.d.ts +4 -0
- package/dist/workflow/Workflow.d.ts.map +1 -1
- package/dist/workflow/Workflow.js.map +1 -1
- package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
- package/dist/workflow/WorkflowEngine.js +5 -0
- package/dist/workflow/WorkflowEngine.js.map +1 -1
- package/package.json +7 -3
- package/src/BigDecimal.ts +170 -16
- package/src/ByteSize.ts +29 -14
- package/src/Equal.ts +3 -3
- package/src/Hash.ts +5 -4
- package/src/Iterable.ts +28 -19
- package/src/JsonSchema.ts +45 -7
- package/src/MutableRef.ts +1 -8
- package/src/Path.ts +6 -1
- package/src/Pool.ts +2 -1
- package/src/Ref.ts +0 -8
- package/src/Schedule.ts +8 -6
- package/src/Schema.ts +3 -2
- package/src/SchemaRepresentation.ts +4 -2
- package/src/SchemaTransformation.ts +2 -2
- package/src/Stream.ts +6 -5
- package/src/ai/McpClient.ts +488 -91
- package/src/ai/McpSchema.ts +119 -0
- package/src/ai/McpServer.ts +302 -56
- package/src/ai/Prompt.ts +16 -11
- package/src/ai/Tool.ts +5 -10
- package/src/ai/internal/mcpCore.ts +165 -12
- package/src/ai/internal/mcpProtocol/v2024_11_05.ts +3 -1
- package/src/ai/internal/mcpProtocol/v2025_03_26.ts +3 -1
- package/src/ai/internal/mcpProtocol/v2025_06_18.ts +3 -1
- package/src/ai/internal/mcpProtocol/v2025_11_25.ts +3 -1
- package/src/ai/internal/mcpProtocol/v2026_07_28.ts +42 -9
- package/src/ai/internal/mcpProtocol.ts +15 -0
- package/src/ai/internal/mcpRuntime.ts +6 -3
- package/src/ai/internal/mcpSkills.ts +480 -0
- package/src/ai/internal/structured-output.ts +10 -4
- package/src/cluster/ClusterWorkflowEngine.ts +48 -33
- package/src/cluster/Entity.ts +52 -0
- package/src/cluster/MessageStorage.ts +3 -6
- package/src/cluster/Reply.ts +1 -1
- package/src/cluster/Runners.ts +16 -2
- package/src/cluster/Sharding.ts +17 -1
- package/src/cluster/internal/clusterAbandon.ts +7 -7
- package/src/cluster/internal/entityManager.ts +89 -15
- package/src/cluster/internal/transactionNotifications.ts +7 -0
- package/src/crypto/Aead.ts +3 -3
- package/src/crypto/Cipher.ts +3 -3
- package/src/crypto/KeyAgreement.ts +4 -4
- package/src/crypto/KeyFormat.ts +30 -1
- package/src/crypto/KeyWrap.ts +6 -6
- package/src/crypto/Mac.ts +3 -3
- package/src/crypto/Signature.ts +4 -4
- package/src/crypto/WebCrypto.ts +20 -0
- package/src/crypto/internal/asymmetric.ts +2 -1
- package/src/crypto/internal/key.ts +12 -5
- package/src/encoding/Base64Url.ts +27 -3
- package/src/encoding/Json5.ts +59 -0
- package/src/encoding/Jsonc.ts +126 -0
- package/src/encoding/Ndjson.ts +6 -5
- package/src/encoding/SchemaBinary.ts +228 -7
- package/src/encoding/Sse.ts +5 -3
- package/src/encoding/index.ts +12 -0
- package/src/eventlog/EventLog.ts +7 -0
- package/src/eventlog/EventLogServer.ts +67 -24
- package/src/eventlog/EventLogServerEncrypted.ts +5 -0
- package/src/eventlog/EventLogServerUnencrypted.ts +19 -2
- package/src/eventlog/EventLogSessionAuth.ts +26 -0
- package/src/graphql/GraphQLClient.ts +3 -1
- package/src/graphql/GraphQLClientError.ts +15 -22
- package/src/graphql/GraphQLProtocol.ts +12 -3
- package/src/http/HttpClient.ts +244 -33
- package/src/http/HttpServerRequest.ts +61 -23
- package/src/http/internal/mimeTypes.ts +4 -1
- package/src/http-api/HttpApiSchema.ts +1 -1
- package/src/internal/dateTime.ts +80 -27
- package/src/internal/effect.ts +6 -0
- package/src/internal/glob.ts +279 -63
- package/src/internal/graphql.ts +27 -9
- package/src/internal/graphqlHeaders.ts +13 -0
- package/src/internal/jsonParser.ts +307 -0
- package/src/internal/persistence.ts +9 -1
- package/src/internal/request.ts +51 -58
- package/src/internal/schema/fromJsonSchemaDocument.ts +11 -10
- package/src/internal/sql.ts +25 -0
- package/src/internal/version.ts +1 -1
- package/src/jose/JoseError.ts +329 -0
- package/src/jose/Jwe.ts +196 -0
- package/src/jose/Jwk.ts +777 -0
- package/src/jose/Jwks.ts +418 -0
- package/src/jose/Jws.ts +312 -0
- package/src/jose/Jwt.ts +493 -0
- package/src/jose/index.ts +58 -0
- package/src/jose/internal/compact.ts +195 -0
- package/src/net/Host.ts +5 -10
- package/src/observability/OtlpExporter.ts +42 -18
- package/src/observability/OtlpSerialization.ts +13 -5
- package/src/observability/internal/otlpProtobuf.ts +6 -6
- package/src/observability/internal/protobuf.ts +10 -0
- package/src/persistence/CircuitBreaker.ts +113 -48
- package/src/persistence/RateLimiter.ts +97 -19
- package/src/persistence/index.ts +1 -1
- package/src/reactivity/AtomRegistry.ts +19 -8
- package/src/rpc/Rpc.ts +3 -1
- package/src/rpc/RpcClient.ts +44 -24
- package/src/rpc/RpcMessage.ts +3 -2
- package/src/rpc/RpcServer.ts +12 -1
- package/src/sql/Migrator.ts +35 -18
- package/src/sql/SqlClient.ts +91 -22
- package/src/sql/Statement.ts +60 -35
- package/src/workflow/Workflow.ts +4 -0
- package/src/workflow/WorkflowEngine.ts +5 -0
|
@@ -972,6 +972,139 @@ export function fieldId(id: number) {
|
|
|
972
972
|
|
|
973
973
|
const FIELD_ID_ANNOTATION_KEY = "~effect/encoding/SchemaBinary/fieldId"
|
|
974
974
|
|
|
975
|
+
// Marks the check that opts a number or bigint into a fixed-width encoding.
|
|
976
|
+
// It lives on a check, not the AST, so later annotations and checks keep it.
|
|
977
|
+
const FIXED_WIDTH_ANNOTATION_KEY = "~effect/encoding/SchemaBinary/fixedWidth"
|
|
978
|
+
|
|
979
|
+
type FixedWidthKind = "i32" | "u32" | "i64" | "u64"
|
|
980
|
+
|
|
981
|
+
const BIGINT_I64_MIN = BigInt("-9223372036854775808")
|
|
982
|
+
const BIGINT_I64_MAX = BigInt("9223372036854775807")
|
|
983
|
+
const BIGINT_U64_MAX = BigInt("18446744073709551615")
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* A 32-bit signed integer written as four little-endian bytes.
|
|
987
|
+
*
|
|
988
|
+
* **When to use**
|
|
989
|
+
*
|
|
990
|
+
* Use when values regularly need more than four bytes as a varint, such as
|
|
991
|
+
* hashes or full-range ids. Small values are cheaper as `Schema.Int`.
|
|
992
|
+
*
|
|
993
|
+
* **Details**
|
|
994
|
+
*
|
|
995
|
+
* Rejects non-integers and values outside -2147483648 through 2147483647
|
|
996
|
+
* instead of truncating them. `-0` is written as `0`.
|
|
997
|
+
*
|
|
998
|
+
* **Gotchas**
|
|
999
|
+
*
|
|
1000
|
+
* Switching a field between this, {@link uint32}, `Schema.Number` or
|
|
1001
|
+
* `Schema.Int` changes its encoding, so it is not a compatible evolution. In
|
|
1002
|
+
* default mode the other reader can decode a different value without an error,
|
|
1003
|
+
* for example after a signedness swap or inside an array of structs.
|
|
1004
|
+
* Fingerprint mode rejects the layout mismatch.
|
|
1005
|
+
*
|
|
1006
|
+
* **Example** (Declaring fixed-width integer fields)
|
|
1007
|
+
*
|
|
1008
|
+
* ```ts
|
|
1009
|
+
* import { Schema } from "effect"
|
|
1010
|
+
* import { SchemaBinary } from "effect/encoding"
|
|
1011
|
+
*
|
|
1012
|
+
* const Packet = Schema.Struct({
|
|
1013
|
+
* version: SchemaBinary.uint32,
|
|
1014
|
+
* offset: SchemaBinary.int32,
|
|
1015
|
+
* sequence: SchemaBinary.uint64,
|
|
1016
|
+
* timestamp: SchemaBinary.int64
|
|
1017
|
+
* })
|
|
1018
|
+
* ```
|
|
1019
|
+
*
|
|
1020
|
+
* @stability unstable
|
|
1021
|
+
* @category schemas
|
|
1022
|
+
* @since 4.0.0
|
|
1023
|
+
*/
|
|
1024
|
+
export const int32: Schema.Number = Schema.Number.check(
|
|
1025
|
+
Schema.isInt32({ [FIXED_WIDTH_ANNOTATION_KEY]: "i32" })
|
|
1026
|
+
)
|
|
1027
|
+
|
|
1028
|
+
/**
|
|
1029
|
+
* A 32-bit unsigned integer written as four little-endian bytes.
|
|
1030
|
+
*
|
|
1031
|
+
* **Details**
|
|
1032
|
+
*
|
|
1033
|
+
* Rejects non-integers and values outside 0 through 4294967295 instead of
|
|
1034
|
+
* wrapping them. See {@link int32} for when a fixed width pays off.
|
|
1035
|
+
*
|
|
1036
|
+
* @stability unstable
|
|
1037
|
+
* @category schemas
|
|
1038
|
+
* @since 4.0.0
|
|
1039
|
+
*/
|
|
1040
|
+
export const uint32: Schema.Number = Schema.Number.check(
|
|
1041
|
+
Schema.isUint32({ [FIXED_WIDTH_ANNOTATION_KEY]: "u32" })
|
|
1042
|
+
)
|
|
1043
|
+
|
|
1044
|
+
/**
|
|
1045
|
+
* A 64-bit signed integer, as a `bigint`, written as eight little-endian bytes.
|
|
1046
|
+
*
|
|
1047
|
+
* **Details**
|
|
1048
|
+
*
|
|
1049
|
+
* Rejects values outside -2^63 through 2^63 - 1 instead of wrapping them. As a
|
|
1050
|
+
* struct field it costs one length byte more than the payload, because the
|
|
1051
|
+
* eight-byte field kind belongs to floating-point numbers.
|
|
1052
|
+
*
|
|
1053
|
+
* **Gotchas**
|
|
1054
|
+
*
|
|
1055
|
+
* Switching a field between this, {@link uint64} or `Schema.BigInt` is not a
|
|
1056
|
+
* compatible evolution. All three are length-prefixed struct fields, and eight
|
|
1057
|
+
* bytes can be valid for each, so a default-mode reader may decode the other
|
|
1058
|
+
* form as a different value without an error. Fingerprint mode rejects the
|
|
1059
|
+
* layout mismatch.
|
|
1060
|
+
*
|
|
1061
|
+
* @stability unstable
|
|
1062
|
+
* @category schemas
|
|
1063
|
+
* @since 4.0.0
|
|
1064
|
+
*/
|
|
1065
|
+
export const int64: Schema.BigInt = Schema.BigInt.check(
|
|
1066
|
+
Schema.isBetweenBigInt({ minimum: BIGINT_I64_MIN, maximum: BIGINT_I64_MAX }, {
|
|
1067
|
+
expected: "a 64-bit integer",
|
|
1068
|
+
[FIXED_WIDTH_ANNOTATION_KEY]: "i64"
|
|
1069
|
+
})
|
|
1070
|
+
)
|
|
1071
|
+
|
|
1072
|
+
/**
|
|
1073
|
+
* A 64-bit unsigned integer, as a `bigint`, written as eight little-endian
|
|
1074
|
+
* bytes.
|
|
1075
|
+
*
|
|
1076
|
+
* **Details**
|
|
1077
|
+
*
|
|
1078
|
+
* Rejects values outside 0 through 2^64 - 1 instead of wrapping them. See
|
|
1079
|
+
* {@link int64} for the struct field cost.
|
|
1080
|
+
*
|
|
1081
|
+
* **Gotchas**
|
|
1082
|
+
*
|
|
1083
|
+
* Switching a field between this, {@link int64} or `Schema.BigInt` can decode
|
|
1084
|
+
* as a different value without an error in default mode; see {@link int64}.
|
|
1085
|
+
*
|
|
1086
|
+
* @stability unstable
|
|
1087
|
+
* @category schemas
|
|
1088
|
+
* @since 4.0.0
|
|
1089
|
+
*/
|
|
1090
|
+
export const uint64: Schema.BigInt = Schema.BigInt.check(
|
|
1091
|
+
Schema.isBetweenBigInt({ minimum: BigInt(0), maximum: BIGINT_U64_MAX }, {
|
|
1092
|
+
expected: "a 64-bit unsigned integer",
|
|
1093
|
+
[FIXED_WIDTH_ANNOTATION_KEY]: "u64"
|
|
1094
|
+
})
|
|
1095
|
+
)
|
|
1096
|
+
|
|
1097
|
+
// The fixed width the schema opted into, from any of its checks.
|
|
1098
|
+
function fixedWidthKind(ast: SchemaAST.AST): FixedWidthKind | undefined {
|
|
1099
|
+
const checks = ast.checks
|
|
1100
|
+
if (checks === undefined) return undefined
|
|
1101
|
+
for (const check of checks) {
|
|
1102
|
+
const kind = check.annotations?.[FIXED_WIDTH_ANNOTATION_KEY]
|
|
1103
|
+
if (kind !== undefined) return kind as FixedWidthKind
|
|
1104
|
+
}
|
|
1105
|
+
return undefined
|
|
1106
|
+
}
|
|
1107
|
+
|
|
975
1108
|
// Bit 0 selects fingerprint mode; all other flag bits are reserved.
|
|
976
1109
|
const ENVELOPE = 0x20 // version nibble 2, flags 0
|
|
977
1110
|
const ENVELOPE_FINGERPRINT = 0x21 // version nibble 2, flag bit 0
|
|
@@ -1370,6 +1503,11 @@ class Writer {
|
|
|
1370
1503
|
this.view.setBigInt64(this.start + this.len, n, true)
|
|
1371
1504
|
this.len += 8
|
|
1372
1505
|
}
|
|
1506
|
+
u64(n: bigint) {
|
|
1507
|
+
this.ensure(8)
|
|
1508
|
+
this.view.setBigUint64(this.start + this.len, n, true)
|
|
1509
|
+
this.len += 8
|
|
1510
|
+
}
|
|
1373
1511
|
u32le(n: number) {
|
|
1374
1512
|
this.ensure(4)
|
|
1375
1513
|
this.view.setUint32(this.start + this.len, n >>> 0, true)
|
|
@@ -1801,6 +1939,12 @@ class Reader {
|
|
|
1801
1939
|
this.pos += 8
|
|
1802
1940
|
return value
|
|
1803
1941
|
}
|
|
1942
|
+
u64(): bigint {
|
|
1943
|
+
if (this.pos + 8 > this.end) invalid("complete value", undefined, this.options)
|
|
1944
|
+
const value = (this.view ?? this.dataView()).getBigUint64(this.pos, true)
|
|
1945
|
+
this.pos += 8
|
|
1946
|
+
return value
|
|
1947
|
+
}
|
|
1804
1948
|
u32le(): number {
|
|
1805
1949
|
if (this.pos + 4 > this.end) invalid("complete value", undefined, this.options)
|
|
1806
1950
|
const value = (this.view ?? this.dataView()).getUint32(this.pos, true)
|
|
@@ -1825,6 +1969,7 @@ type LeafKind =
|
|
|
1825
1969
|
| "symbol"
|
|
1826
1970
|
| "bytes"
|
|
1827
1971
|
| "bigint"
|
|
1972
|
+
| FixedWidthKind
|
|
1828
1973
|
| "json"
|
|
1829
1974
|
| "duration"
|
|
1830
1975
|
| "bigDecimal"
|
|
@@ -2007,7 +2152,12 @@ function packedSize(layout: Layout): number | undefined {
|
|
|
2007
2152
|
return packedSize(layout.leaf)
|
|
2008
2153
|
case "bool":
|
|
2009
2154
|
return 1
|
|
2155
|
+
case "i32":
|
|
2156
|
+
case "u32":
|
|
2157
|
+
return 4
|
|
2010
2158
|
case "int64":
|
|
2159
|
+
case "i64":
|
|
2160
|
+
case "u64":
|
|
2011
2161
|
return 8
|
|
2012
2162
|
default:
|
|
2013
2163
|
return undefined
|
|
@@ -2318,10 +2468,15 @@ function compileLayout(root: SchemaAST.AST): CompiledLayout {
|
|
|
2318
2468
|
case "Undefined":
|
|
2319
2469
|
case "Void":
|
|
2320
2470
|
return leaf("undefined")
|
|
2321
|
-
case "Number":
|
|
2471
|
+
case "Number": {
|
|
2472
|
+
const fixed = fixedWidthKind(ast)
|
|
2473
|
+
if (fixed === "i32" || fixed === "u32") return leaf(fixed)
|
|
2322
2474
|
return leaf(provesInteger(ast) ? "int" : "number")
|
|
2323
|
-
|
|
2324
|
-
|
|
2475
|
+
}
|
|
2476
|
+
case "BigInt": {
|
|
2477
|
+
const fixed = fixedWidthKind(ast)
|
|
2478
|
+
return leaf(fixed === "i64" || fixed === "u64" ? fixed : "bigint")
|
|
2479
|
+
}
|
|
2325
2480
|
case "Literal":
|
|
2326
2481
|
return literalLayout(leaf(literalKind(ast.literal)), [ast.literal])
|
|
2327
2482
|
case "Unknown":
|
|
@@ -2685,7 +2840,7 @@ function isExact(root: SchemaAST.AST): boolean {
|
|
|
2685
2840
|
const walked = new Map<SchemaAST.AST, boolean>()
|
|
2686
2841
|
const exact = (ast: SchemaAST.AST): boolean => {
|
|
2687
2842
|
if (
|
|
2688
|
-
ast.encoding !== undefined || ast.checks !== undefined ||
|
|
2843
|
+
ast.encoding !== undefined || (ast.checks !== undefined && !isFixedWidthOnly(ast)) ||
|
|
2689
2844
|
(ast as { readonly encodingChecks?: SchemaAST.Checks }).encodingChecks !== undefined
|
|
2690
2845
|
) {
|
|
2691
2846
|
return false
|
|
@@ -2746,6 +2901,13 @@ function isExact(root: SchemaAST.AST): boolean {
|
|
|
2746
2901
|
return exact(root)
|
|
2747
2902
|
}
|
|
2748
2903
|
|
|
2904
|
+
// The binary layer enforces a fixed-width check on its own, so it is exact
|
|
2905
|
+
// when no other check rides along.
|
|
2906
|
+
function isFixedWidthOnly(ast: SchemaAST.AST): boolean {
|
|
2907
|
+
return (ast._tag === "Number" || ast._tag === "BigInt") && ast.checks?.length === 1 &&
|
|
2908
|
+
fixedWidthKind(ast) !== undefined
|
|
2909
|
+
}
|
|
2910
|
+
|
|
2749
2911
|
// A clean Exit whose success schema is exact: the binary layer fully produces
|
|
2750
2912
|
// and validates success exits, so only failure exits need the schema pass for
|
|
2751
2913
|
// their cause's error and defect encodings.
|
|
@@ -2784,7 +2946,11 @@ const F = {
|
|
|
2784
2946
|
exit: 22,
|
|
2785
2947
|
cause: 23,
|
|
2786
2948
|
causeReason: 24,
|
|
2787
|
-
literal: 25
|
|
2949
|
+
literal: 25,
|
|
2950
|
+
i32: 26,
|
|
2951
|
+
u32: 27,
|
|
2952
|
+
i64: 28,
|
|
2953
|
+
u64: 29
|
|
2788
2954
|
} as const
|
|
2789
2955
|
|
|
2790
2956
|
// Hash the compiled layout graph, including cycle back-edge distances.
|
|
@@ -2828,6 +2994,10 @@ function layoutFingerprint(root: Layout): bigint {
|
|
|
2828
2994
|
case "symbol":
|
|
2829
2995
|
case "bytes":
|
|
2830
2996
|
case "bigint":
|
|
2997
|
+
case "i32":
|
|
2998
|
+
case "u32":
|
|
2999
|
+
case "i64":
|
|
3000
|
+
case "u64":
|
|
2831
3001
|
case "json":
|
|
2832
3002
|
case "duration":
|
|
2833
3003
|
case "bigDecimal":
|
|
@@ -2986,12 +3156,16 @@ function matchesLayout(layout: Layout, value: unknown): boolean {
|
|
|
2986
3156
|
return value === undefined
|
|
2987
3157
|
case "number":
|
|
2988
3158
|
case "int":
|
|
3159
|
+
case "i32":
|
|
3160
|
+
case "u32":
|
|
2989
3161
|
return typeof value === "number"
|
|
2990
3162
|
case "string":
|
|
2991
3163
|
return typeof value === "string"
|
|
2992
3164
|
case "symbol":
|
|
2993
3165
|
return typeof value === "symbol"
|
|
2994
3166
|
case "bigint":
|
|
3167
|
+
case "i64":
|
|
3168
|
+
case "u64":
|
|
2995
3169
|
return typeof value === "bigint"
|
|
2996
3170
|
case "bytes":
|
|
2997
3171
|
return value instanceof Uint8Array
|
|
@@ -3287,6 +3461,10 @@ function valueWireCode(layout: Layout, value: unknown, options: SchemaAST.ParseO
|
|
|
3287
3461
|
case "int":
|
|
3288
3462
|
if (!Number.isSafeInteger(value)) encodeFail("an integer", value, options)
|
|
3289
3463
|
return FIELD_WIRE_VARINT
|
|
3464
|
+
// The payload write validates the value.
|
|
3465
|
+
case "i32":
|
|
3466
|
+
case "u32":
|
|
3467
|
+
return FIELD_WIRE_FIXED32
|
|
3290
3468
|
default:
|
|
3291
3469
|
return FIELD_WIRE_SIZED
|
|
3292
3470
|
}
|
|
@@ -3295,8 +3473,8 @@ function valueWireCode(layout: Layout, value: unknown, options: SchemaAST.ParseO
|
|
|
3295
3473
|
function encodeWirePayload(ctx: EncodeContext, layout: Layout, value: unknown, wire: number, w: Writer) {
|
|
3296
3474
|
const kind = wire % FIELD_WIRE_FACTOR
|
|
3297
3475
|
switch (kind) {
|
|
3298
|
-
// EMPTY
|
|
3299
|
-
//
|
|
3476
|
+
// EMPTY is decoder-side skip support only; `valueWireCode` never produces
|
|
3477
|
+
// it.
|
|
3300
3478
|
case FIELD_WIRE_FALSE:
|
|
3301
3479
|
case FIELD_WIRE_TRUE:
|
|
3302
3480
|
return
|
|
@@ -3306,6 +3484,9 @@ function encodeWirePayload(ctx: EncodeContext, layout: Layout, value: unknown, w
|
|
|
3306
3484
|
case FIELD_WIRE_FIXED64:
|
|
3307
3485
|
w.f64(value as number)
|
|
3308
3486
|
return
|
|
3487
|
+
case FIELD_WIRE_FIXED32:
|
|
3488
|
+
encodeValue(ctx, layout, value, w)
|
|
3489
|
+
return
|
|
3309
3490
|
case FIELD_WIRE_DECIMAL: {
|
|
3310
3491
|
const scale = Math.floor(wire / FIELD_WIRE_FACTOR)
|
|
3311
3492
|
w.numberVarint(Math.round((value as number) * POW10[scale]))
|
|
@@ -4010,6 +4191,29 @@ function encodeValue(ctx: EncodeContext, layout: Layout, value: unknown, w: Writ
|
|
|
4010
4191
|
if (typeof value !== "bigint") encodeFail("a bigint", value, ctx.options)
|
|
4011
4192
|
w.zigzag(value)
|
|
4012
4193
|
return
|
|
4194
|
+
// `disableChecks` can bypass the range check used to select these layouts.
|
|
4195
|
+
case "i32":
|
|
4196
|
+
if (typeof value !== "number" || (value | 0) !== value) encodeFail("a 32-bit integer", value, ctx.options)
|
|
4197
|
+
w.i32le(value)
|
|
4198
|
+
return
|
|
4199
|
+
case "u32":
|
|
4200
|
+
if (typeof value !== "number" || value >>> 0 !== value) {
|
|
4201
|
+
encodeFail("a 32-bit unsigned integer", value, ctx.options)
|
|
4202
|
+
}
|
|
4203
|
+
w.u32le(value)
|
|
4204
|
+
return
|
|
4205
|
+
case "i64":
|
|
4206
|
+
if (typeof value !== "bigint" || value < BIGINT_I64_MIN || value > BIGINT_I64_MAX) {
|
|
4207
|
+
encodeFail("a 64-bit integer", value, ctx.options)
|
|
4208
|
+
}
|
|
4209
|
+
w.i64(value)
|
|
4210
|
+
return
|
|
4211
|
+
case "u64":
|
|
4212
|
+
if (typeof value !== "bigint" || value < BIGINT_ZERO || value > BIGINT_U64_MAX) {
|
|
4213
|
+
encodeFail("a 64-bit unsigned integer", value, ctx.options)
|
|
4214
|
+
}
|
|
4215
|
+
w.u64(value)
|
|
4216
|
+
return
|
|
4013
4217
|
case "int64": {
|
|
4014
4218
|
if (!matchesLayout(layout, value)) {
|
|
4015
4219
|
encodeFail(layout.flavor === "date" ? "a Date" : "a DateTime.Utc", value, ctx.options)
|
|
@@ -4375,6 +4579,9 @@ function fieldWireMask(layout: Layout): number {
|
|
|
4375
4579
|
return (1 << FIELD_WIRE_VARINT) | (1 << FIELD_WIRE_FIXED64) | (1 << FIELD_WIRE_DECIMAL)
|
|
4376
4580
|
case "int":
|
|
4377
4581
|
return 1 << FIELD_WIRE_VARINT
|
|
4582
|
+
case "i32":
|
|
4583
|
+
case "u32":
|
|
4584
|
+
return 1 << FIELD_WIRE_FIXED32
|
|
4378
4585
|
default:
|
|
4379
4586
|
return 1 << FIELD_WIRE_SIZED
|
|
4380
4587
|
}
|
|
@@ -4406,6 +4613,8 @@ function decodeFieldPayload(layout: Layout, wireMask: number, kind: number, r: R
|
|
|
4406
4613
|
skipFieldPayload(kind, r)
|
|
4407
4614
|
return ABSENT
|
|
4408
4615
|
}
|
|
4616
|
+
// Only the two 32-bit layouts accept this kind, so the payload needs no window.
|
|
4617
|
+
if (kind === FIELD_WIRE_FIXED32) return layout._ === "u32" ? r.u32le() : r.i32le()
|
|
4409
4618
|
if (kind !== FIELD_WIRE_SIZED) {
|
|
4410
4619
|
const value = decodeScalarField(kind, r)
|
|
4411
4620
|
if (layout._ === "literal" && !hasLiteral(layout, value)) {
|
|
@@ -4993,6 +5202,18 @@ function decodeValueUnchecked(layout: Layout, r: Reader): unknown {
|
|
|
4993
5202
|
return r.takeCopy(r.end - r.pos)
|
|
4994
5203
|
case "bigint":
|
|
4995
5204
|
return r.zigzag()
|
|
5205
|
+
case "i32":
|
|
5206
|
+
if (r.remaining !== 4) invalid("a 32-bit integer", undefined, r.options)
|
|
5207
|
+
return r.i32le()
|
|
5208
|
+
case "u32":
|
|
5209
|
+
if (r.remaining !== 4) invalid("a 32-bit unsigned integer", undefined, r.options)
|
|
5210
|
+
return r.u32le()
|
|
5211
|
+
case "i64":
|
|
5212
|
+
if (r.remaining !== 8) invalid("a 64-bit integer", undefined, r.options)
|
|
5213
|
+
return r.i64()
|
|
5214
|
+
case "u64":
|
|
5215
|
+
if (r.remaining !== 8) invalid("a 64-bit unsigned integer", undefined, r.options)
|
|
5216
|
+
return r.u64()
|
|
4996
5217
|
case "int64": {
|
|
4997
5218
|
if (r.remaining !== 8) invalid("int64", undefined, r.options)
|
|
4998
5219
|
const millis = Number(r.i64())
|
package/src/encoding/Sse.ts
CHANGED
|
@@ -667,7 +667,9 @@ export type AnyEvent = Event | Retry
|
|
|
667
667
|
* **Details**
|
|
668
668
|
*
|
|
669
669
|
* It renders `Event` values as `id`, `event`, and `data` lines and renders
|
|
670
|
-
* `Retry` values as `retry:` directives.
|
|
670
|
+
* `Retry` values as `retry:` directives. CR and LF are removed from `id` and
|
|
671
|
+
* `event`, and NUL is removed from `id`, so those values cannot inject fields
|
|
672
|
+
* or events.
|
|
671
673
|
*
|
|
672
674
|
* @stability unstable
|
|
673
675
|
* @category encoding
|
|
@@ -679,10 +681,10 @@ export const encoder: Encoder = {
|
|
|
679
681
|
case "Event": {
|
|
680
682
|
let data = ""
|
|
681
683
|
if (event.id !== undefined) {
|
|
682
|
-
data += `id: ${event.id}\n`
|
|
684
|
+
data += `id: ${event.id.replace(/[\r\n\0]/g, "")}\n`
|
|
683
685
|
}
|
|
684
686
|
if (event.event !== "message") {
|
|
685
|
-
data += `event: ${event.event}\n`
|
|
687
|
+
data += `event: ${event.event.replace(/[\r\n]/g, "")}\n`
|
|
686
688
|
}
|
|
687
689
|
data += `data: ${event.data.replace(/\r\n|\r|\n/g, "\ndata: ")}\n`
|
|
688
690
|
return data + "\n"
|
package/src/encoding/index.ts
CHANGED
|
@@ -41,12 +41,24 @@ export * as Hex from "./Hex.ts"
|
|
|
41
41
|
*/
|
|
42
42
|
export * as Ini from "./Ini.ts"
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* @stability unstable
|
|
46
|
+
* @since 4.1.2
|
|
47
|
+
*/
|
|
48
|
+
export * as Json5 from "./Json5.ts"
|
|
49
|
+
|
|
44
50
|
/**
|
|
45
51
|
* @stability unstable
|
|
46
52
|
* @since 4.0.6
|
|
47
53
|
*/
|
|
48
54
|
export * as JsonArray from "./JsonArray.ts"
|
|
49
55
|
|
|
56
|
+
/**
|
|
57
|
+
* @stability unstable
|
|
58
|
+
* @since 4.1.2
|
|
59
|
+
*/
|
|
60
|
+
export * as Jsonc from "./Jsonc.ts"
|
|
61
|
+
|
|
50
62
|
/**
|
|
51
63
|
* @stability unstable
|
|
52
64
|
* @since 4.0.0
|
package/src/eventlog/EventLog.ts
CHANGED
|
@@ -303,6 +303,13 @@ export const layerRegistry = Layer.effect(
|
|
|
303
303
|
* The identity is used by remote replication for authentication and by the
|
|
304
304
|
* encryption service to derive signing and encryption keys.
|
|
305
305
|
*
|
|
306
|
+
* **Gotchas**
|
|
307
|
+
*
|
|
308
|
+
* `publicKey` identifies the identity but is not a secret, and nothing ties it
|
|
309
|
+
* to the signing key derived from `privateKey`. A server binds the first
|
|
310
|
+
* signing key that authenticates for a `publicKey`, unless its authorization
|
|
311
|
+
* checks the presented signing key.
|
|
312
|
+
*
|
|
306
313
|
* @stability unstable
|
|
307
314
|
* @category services
|
|
308
315
|
* @since 4.0.0
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
import type { NonEmptyReadonlyArray } from "../Array.ts"
|
|
13
13
|
import * as Arr from "../Array.ts"
|
|
14
14
|
import * as Cache from "../Cache.ts"
|
|
15
|
+
import * as Clock from "../Clock.ts"
|
|
15
16
|
import * as Context from "../Context.ts"
|
|
17
|
+
import * as Mac from "../crypto/Mac.ts"
|
|
16
18
|
import * as Data from "../Data.ts"
|
|
17
19
|
import * as Duration from "../Duration.ts"
|
|
18
20
|
import * as Effect from "../Effect.ts"
|
|
@@ -21,7 +23,6 @@ import * as Exit from "../Exit.ts"
|
|
|
21
23
|
import * as Hash from "../Hash.ts"
|
|
22
24
|
import * as Uuid from "../internal/uuid.ts"
|
|
23
25
|
import * as Layer from "../Layer.ts"
|
|
24
|
-
import * as Option from "../Option.ts"
|
|
25
26
|
import * as Redacted from "../Redacted.ts"
|
|
26
27
|
import type * as Rpc from "../rpc/Rpc.ts"
|
|
27
28
|
import type * as RpcGroup from "../rpc/RpcGroup.ts"
|
|
@@ -76,6 +77,12 @@ export const layerAuthMiddleware: Layer.Layer<
|
|
|
76
77
|
* chunked writes, delegates write and change handling to the supplied callbacks,
|
|
77
78
|
* and frames large change payloads into chunks.
|
|
78
79
|
*
|
|
80
|
+
* `Authenticate` calls `authorizeIdentity` with the claimed public key and the
|
|
81
|
+
* presented signing public key, then verifies the signature against the
|
|
82
|
+
* presented key. Only a verified key is passed to
|
|
83
|
+
* `getOrCreateSessionAuthBinding`, and a key that differs from the identity's
|
|
84
|
+
* existing binding is rejected.
|
|
85
|
+
*
|
|
79
86
|
* Use the connection's `ConnectionWrites.track` in `onWrite` and
|
|
80
87
|
* `ConnectionWrites.filter` in `changes` to suppress its own write echoes.
|
|
81
88
|
* `compaction` sets `HelloResponse.compaction`, advertising that the server
|
|
@@ -89,7 +96,10 @@ export const layerRpcHandlers = (options: {
|
|
|
89
96
|
readonly remoteId: RemoteId
|
|
90
97
|
readonly firstSequence?: number | undefined
|
|
91
98
|
readonly compaction?: boolean | undefined
|
|
92
|
-
readonly authorizeIdentity?: (
|
|
99
|
+
readonly authorizeIdentity?: (
|
|
100
|
+
publicKey: string,
|
|
101
|
+
signingPublicKey: Uint8Array<ArrayBuffer>
|
|
102
|
+
) => Effect.Effect<void, EventLogProtocolError>
|
|
93
103
|
readonly getOrCreateSessionAuthBinding: (
|
|
94
104
|
publicKey: string,
|
|
95
105
|
signingPublicKey: Uint8Array<ArrayBuffer>
|
|
@@ -109,11 +119,6 @@ export const layerRpcHandlers = (options: {
|
|
|
109
119
|
Rpc.ToHandler<RpcGroup.Rpcs<typeof EventLogRemoteRpcs>> | EventLogAuthentication
|
|
110
120
|
> =>
|
|
111
121
|
EventLogRemoteRpcs.toLayer(Effect.gen(function*() {
|
|
112
|
-
const clientChallenges = yield* Cache.make({
|
|
113
|
-
lookup: (_clientId: number) => Effect.orDie(EventLogSessionAuth.makeSessionAuthChallenge),
|
|
114
|
-
capacity: Number.MAX_SAFE_INTEGER,
|
|
115
|
-
timeToLive: EventLogSessionAuth.SessionAuthChallengeTimeToLiveMillis
|
|
116
|
-
})
|
|
117
122
|
const toFrames = makeFramer()
|
|
118
123
|
|
|
119
124
|
const persistedSigningPublicKeys = yield* Cache.makeWith(
|
|
@@ -138,17 +143,31 @@ export const layerRpcHandlers = (options: {
|
|
|
138
143
|
|
|
139
144
|
return EventLogRemoteRpcs.of({
|
|
140
145
|
"EventLog.Hello": Effect.fnUntraced(function*(_, { client }) {
|
|
141
|
-
|
|
146
|
+
// Kept on the connection, so it is released when the client disconnects
|
|
147
|
+
// and shared by overlapping Hellos until `Authenticate` consumes it.
|
|
148
|
+
let pending = getPendingChallenge(client, yield* Clock.currentTimeMillis)
|
|
149
|
+
if (pending === undefined) {
|
|
150
|
+
const challenge = yield* Effect.orDie(EventLogSessionAuth.makeSessionAuthChallenge)
|
|
151
|
+
// Read the clock again, as generating the challenge can suspend. A
|
|
152
|
+
// concurrent Hello may have stored a challenge in the meantime.
|
|
153
|
+
const now = yield* Clock.currentTimeMillis
|
|
154
|
+
pending = getPendingChallenge(client, now) ?? {
|
|
155
|
+
challenge,
|
|
156
|
+
expiresAt: now + EventLogSessionAuth.SessionAuthChallengeTimeToLiveMillis
|
|
157
|
+
}
|
|
158
|
+
client.annotate(PendingChallenge, pending)
|
|
159
|
+
}
|
|
142
160
|
return new HelloResponse({
|
|
143
161
|
remoteId: options.remoteId,
|
|
144
|
-
challenge,
|
|
162
|
+
challenge: pending.challenge,
|
|
145
163
|
firstSequence: options.firstSequence,
|
|
146
164
|
compaction: options.compaction === true ? true : undefined
|
|
147
165
|
})
|
|
148
166
|
}),
|
|
149
167
|
"EventLog.Authenticate": Effect.fnUntraced(function*(request, { client }) {
|
|
150
|
-
const
|
|
151
|
-
|
|
168
|
+
const pending = getPendingChallenge(client, yield* Clock.currentTimeMillis)
|
|
169
|
+
client.annotate(PendingChallenge, undefined)
|
|
170
|
+
if (pending === undefined) {
|
|
152
171
|
return yield* new EventLogProtocolError({
|
|
153
172
|
requestTag: "Authenticate",
|
|
154
173
|
publicKey: request.publicKey,
|
|
@@ -156,35 +175,41 @@ export const layerRpcHandlers = (options: {
|
|
|
156
175
|
message: "Session auth challenge has expired"
|
|
157
176
|
})
|
|
158
177
|
}
|
|
159
|
-
yield* Cache.invalidate(clientChallenges, client.id)
|
|
160
178
|
if (options.authorizeIdentity) {
|
|
161
|
-
yield* options.authorizeIdentity(request.publicKey)
|
|
179
|
+
yield* options.authorizeIdentity(request.publicKey, request.signingPublicKey)
|
|
162
180
|
}
|
|
163
|
-
const signingPublicKey = yield* Cache.get(
|
|
164
|
-
persistedSigningPublicKeys,
|
|
165
|
-
new SessionAuthCacheKey({
|
|
166
|
-
publicKey: request.publicKey,
|
|
167
|
-
signingPublicKey: request.signingPublicKey
|
|
168
|
-
})
|
|
169
|
-
)
|
|
170
181
|
const verified = yield* EventLogSessionAuth.verifySessionAuthenticateRequest({
|
|
171
182
|
remoteId: options.remoteId,
|
|
172
|
-
challenge,
|
|
183
|
+
challenge: pending.challenge,
|
|
173
184
|
publicKey: request.publicKey,
|
|
174
|
-
signingPublicKey,
|
|
185
|
+
signingPublicKey: request.signingPublicKey,
|
|
175
186
|
signature: request.signature,
|
|
176
187
|
algorithm: request.algorithm
|
|
177
188
|
}).pipe(
|
|
178
189
|
Effect.catch(() => Effect.succeed(false))
|
|
179
190
|
)
|
|
180
191
|
|
|
181
|
-
|
|
182
|
-
|
|
192
|
+
const verificationFailed = () =>
|
|
193
|
+
new EventLogProtocolError({
|
|
183
194
|
requestTag: "Authenticate",
|
|
184
195
|
publicKey: request.publicKey,
|
|
185
196
|
code: "Forbidden",
|
|
186
197
|
message: "Session auth signature verification failed"
|
|
187
198
|
})
|
|
199
|
+
if (!verified) {
|
|
200
|
+
return yield* verificationFailed()
|
|
201
|
+
}
|
|
202
|
+
// Only a verified key reaches the binding. A key other than the
|
|
203
|
+
// identity's bound key is rejected like a bad signature.
|
|
204
|
+
const boundSigningPublicKey = yield* Cache.get(
|
|
205
|
+
persistedSigningPublicKeys,
|
|
206
|
+
new SessionAuthCacheKey({
|
|
207
|
+
publicKey: request.publicKey,
|
|
208
|
+
signingPublicKey: request.signingPublicKey
|
|
209
|
+
})
|
|
210
|
+
)
|
|
211
|
+
if (!Mac.timingSafeEqual(boundSigningPublicKey, request.signingPublicKey)) {
|
|
212
|
+
return yield* verificationFailed()
|
|
188
213
|
}
|
|
189
214
|
|
|
190
215
|
const authenticatedIdentities = new Set(
|
|
@@ -392,6 +417,22 @@ class ConnectionWritesState extends Context.Service<ConnectionWritesState, Conne
|
|
|
392
417
|
"effect/eventlog/EventLogServer/ConnectionWrites"
|
|
393
418
|
) {}
|
|
394
419
|
|
|
420
|
+
// The connection's unconsumed `Hello` challenge, cleared by `Authenticate`.
|
|
421
|
+
const PendingChallenge = Context.Reference<
|
|
422
|
+
| {
|
|
423
|
+
readonly challenge: Uint8Array<ArrayBuffer>
|
|
424
|
+
readonly expiresAt: number
|
|
425
|
+
}
|
|
426
|
+
| undefined
|
|
427
|
+
>("effect/eventlog/EventLogServer/PendingChallenge", {
|
|
428
|
+
defaultValue: () => undefined
|
|
429
|
+
})
|
|
430
|
+
|
|
431
|
+
const getPendingChallenge = (client: Rpc.ServerClient, now: number) => {
|
|
432
|
+
const pending = Context.get(client.annotations, PendingChallenge)
|
|
433
|
+
return pending !== undefined && pending.expiresAt > now ? pending : undefined
|
|
434
|
+
}
|
|
435
|
+
|
|
395
436
|
const getConnectionWrites = (client: Rpc.ServerClient): ConnectionWrites => {
|
|
396
437
|
const existing = Context.getOrUndefined(client.annotations, ConnectionWritesState)
|
|
397
438
|
if (existing !== undefined) return existing
|
|
@@ -411,6 +452,8 @@ export class AuthenticatedIdentities extends Context.Service<AuthenticatedIdenti
|
|
|
411
452
|
"effect/eventlog/EventLogServer/AuthenticatedIdentities"
|
|
412
453
|
) {}
|
|
413
454
|
|
|
455
|
+
// Keyed by `publicKey` alone: the cache holds each identity's bound signing
|
|
456
|
+
// key, and `Authenticate` rejects any presented key that differs from it.
|
|
414
457
|
class SessionAuthCacheKey extends Data.Class<{
|
|
415
458
|
readonly publicKey: string
|
|
416
459
|
readonly signingPublicKey: Uint8Array<ArrayBuffer>
|
|
@@ -503,6 +503,11 @@ export class Storage extends Context.Service<Storage, {
|
|
|
503
503
|
* Lowest assigned sequence (default 0). Overestimating skips entries.
|
|
504
504
|
*/
|
|
505
505
|
readonly firstSequence?: number | undefined
|
|
506
|
+
/**
|
|
507
|
+
* Returns the signing key bound to `publicKey`, binding `signingPublicKey`
|
|
508
|
+
* when none is bound yet. The server only passes keys whose signature it
|
|
509
|
+
* has verified, and rejects a key that differs from the returned binding.
|
|
510
|
+
*/
|
|
506
511
|
readonly getOrCreateSessionAuthBinding: (
|
|
507
512
|
publicKey: string,
|
|
508
513
|
signingPublicKey: Uint8Array<ArrayBuffer>
|
|
@@ -165,8 +165,8 @@ export const layerRpcHandlers: Layer.Layer<
|
|
|
165
165
|
return EventLogServer.layerRpcHandlers({
|
|
166
166
|
remoteId,
|
|
167
167
|
firstSequence: storage.firstSequence,
|
|
168
|
-
authorizeIdentity: (publicKey) =>
|
|
169
|
-
auth.authorizeIdentity({ publicKey }).pipe(
|
|
168
|
+
authorizeIdentity: (publicKey, signingPublicKey) =>
|
|
169
|
+
auth.authorizeIdentity({ publicKey, signingPublicKey }).pipe(
|
|
170
170
|
Effect.mapError((error) =>
|
|
171
171
|
new EventLogProtocolError({
|
|
172
172
|
requestTag: "Authenticate",
|
|
@@ -318,6 +318,17 @@ export class EventLogServerAuthError extends Data.TaggedError("EventLogServerAut
|
|
|
318
318
|
* Use to provide authorization checks for plaintext event-log writes, reads,
|
|
319
319
|
* and identity authentication.
|
|
320
320
|
*
|
|
321
|
+
* **Gotchas**
|
|
322
|
+
*
|
|
323
|
+
* An identity's `publicKey` is an identifier, not a secret. The server binds
|
|
324
|
+
* the first signing key that authenticates for an identity and rejects any
|
|
325
|
+
* other key afterwards. `authorizeIdentity` also receives the presented
|
|
326
|
+
* `signingPublicKey`, so a deployment that records each identity's signing key
|
|
327
|
+
* at provisioning time, with `EventLogSessionAuth.deriveSigningPublicKey`, can
|
|
328
|
+
* reject every other key, including on first use. The server always supplies
|
|
329
|
+
* `signingPublicKey`; it is optional only so that existing callers keep
|
|
330
|
+
* compiling, and a policy that checks it should reject when it is missing.
|
|
331
|
+
*
|
|
321
332
|
* @stability unstable
|
|
322
333
|
* @category services
|
|
323
334
|
* @since 4.0.0
|
|
@@ -334,6 +345,7 @@ export class EventLogServerAuthorization extends Context.Service<EventLogServerA
|
|
|
334
345
|
}) => Effect.Effect<void, EventLogServerAuthError>
|
|
335
346
|
readonly authorizeIdentity: (options: {
|
|
336
347
|
readonly publicKey: string
|
|
348
|
+
readonly signingPublicKey?: Uint8Array<ArrayBuffer> | undefined
|
|
337
349
|
}) => Effect.Effect<void, EventLogServerAuthError>
|
|
338
350
|
}>()("effect/eventlog/EventLogServerUnencrypted/EventLogServerAuthorization") {}
|
|
339
351
|
|
|
@@ -422,6 +434,11 @@ export class Storage extends Context.Service<Storage, {
|
|
|
422
434
|
* Lowest assigned sequence (default 0). Overestimating skips entries.
|
|
423
435
|
*/
|
|
424
436
|
readonly firstSequence?: number | undefined
|
|
437
|
+
/**
|
|
438
|
+
* Returns the signing key bound to `publicKey`, binding `signingPublicKey`
|
|
439
|
+
* when none is bound yet. The server only passes keys whose signature it
|
|
440
|
+
* has verified, and rejects a key that differs from the returned binding.
|
|
441
|
+
*/
|
|
425
442
|
readonly getOrCreateSessionAuthBinding: (
|
|
426
443
|
publicKey: string,
|
|
427
444
|
signingPublicKey: Uint8Array<ArrayBuffer>
|