blokctl 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/create/project.d.ts +3 -0
- package/dist/commands/create/project.js +166 -21
- package/dist/commands/create/utils/Examples.d.ts +2 -2
- package/dist/commands/create/utils/Examples.js +9 -3
- package/dist/commands/dev/index.js +13 -1
- package/dist/commands/runtime/add.js +92 -29
- package/dist/commands/runtime/index.js +1 -0
- package/dist/commands/runtime/shared.js +4 -0
- package/dist/scaffold-repo/examples/ts-workflows/mcp-greeter.ts +59 -0
- package/dist/scaffold-repo/examples/ts-workflows/runtime-csharp-hello.ts +36 -0
- package/dist/scaffold-repo/examples/ts-workflows/runtime-go-hello.ts +36 -0
- package/dist/scaffold-repo/examples/ts-workflows/runtime-java-hello.ts +36 -0
- package/dist/scaffold-repo/examples/ts-workflows/runtime-php-hello.ts +36 -0
- package/dist/scaffold-repo/examples/ts-workflows/runtime-python3-hello.ts +36 -0
- package/dist/scaffold-repo/examples/ts-workflows/runtime-ruby-hello.ts +36 -0
- package/dist/scaffold-repo/examples/ts-workflows/runtime-rust-hello.ts +36 -0
- package/dist/scaffold-repo/infra/development/3055.dat +602 -0
- package/dist/scaffold-repo/infra/development/3057.dat +203 -0
- package/dist/scaffold-repo/infra/development/3059.dat +19 -0
- package/dist/scaffold-repo/infra/development/3061.dat +1003 -0
- package/dist/scaffold-repo/infra/development/3062.dat +5465 -0
- package/dist/scaffold-repo/infra/development/3063.dat +1003 -0
- package/dist/scaffold-repo/infra/development/3065.dat +606 -0
- package/dist/scaffold-repo/infra/development/3067.dat +603 -0
- package/dist/scaffold-repo/infra/development/3069.dat +112 -0
- package/dist/scaffold-repo/infra/development/3071.dat +4584 -0
- package/dist/scaffold-repo/infra/development/3073.dat +9 -0
- package/dist/scaffold-repo/infra/development/3075.dat +14599 -0
- package/dist/scaffold-repo/infra/development/3077.dat +16047 -0
- package/dist/scaffold-repo/infra/development/3079.dat +5 -0
- package/dist/scaffold-repo/infra/development/3081.dat +5 -0
- package/dist/scaffold-repo/infra/development/docker-compose.yml +106 -0
- package/dist/scaffold-repo/infra/development/schema.sql +1616 -0
- package/dist/scaffold-repo/infra/development/toc.dat +0 -0
- package/dist/scaffold-repo/infra/metrics/alertmanager.yml +43 -0
- package/dist/scaffold-repo/infra/metrics/alloy-config.alloy +75 -0
- package/dist/scaffold-repo/infra/metrics/dashboard.json +1152 -0
- package/dist/scaffold-repo/infra/metrics/dashboards/blok-overview.json +314 -0
- package/dist/scaffold-repo/infra/metrics/dashboards/blok-system.json +175 -0
- package/dist/scaffold-repo/infra/metrics/dashboards/blok-tracing.json +235 -0
- package/dist/scaffold-repo/infra/metrics/dashboards/blok-triggers.json +258 -0
- package/dist/scaffold-repo/infra/metrics/datasources.yml +43 -0
- package/dist/scaffold-repo/infra/metrics/default.yaml +8 -0
- package/dist/scaffold-repo/infra/metrics/docker-compose.yml +193 -0
- package/dist/scaffold-repo/infra/metrics/loki-config.yaml +50 -0
- package/dist/scaffold-repo/infra/metrics/nginx.conf +25 -0
- package/dist/scaffold-repo/infra/metrics/prometheus.yml +51 -0
- package/dist/scaffold-repo/infra/metrics/rules/blok-alerts.yml +114 -0
- package/dist/scaffold-repo/infra/metrics/telegraf.conf +41 -0
- package/dist/scaffold-repo/infra/metrics/tempo.yaml +81 -0
- package/dist/scaffold-repo/infra/milvus/docker-compose.yml +73 -0
- package/dist/scaffold-repo/sdk/javascript/README.md +151 -0
- package/dist/scaffold-repo/sdk/javascript/bootstrap.min.css +11660 -0
- package/dist/scaffold-repo/sdk/javascript/image-ai.html +316 -0
- package/dist/scaffold-repo/sdk/javascript/nanosdk.js +180 -0
- package/dist/scaffold-repo/sdk/javascript/nanosdk.min.js +100 -0
- package/dist/scaffold-repo/sdk/javascript/pdf.html +63 -0
- package/dist/scaffold-repo/sdk/javascript/test.html +68 -0
- package/dist/scaffold-repo/sdks/CLAUDE.md +67 -0
- package/dist/scaffold-repo/sdks/csharp/.dockerignore +7 -0
- package/dist/scaffold-repo/sdks/csharp/Blok.Core.sln +24 -0
- package/dist/scaffold-repo/sdks/csharp/Dockerfile +42 -0
- package/dist/scaffold-repo/sdks/csharp/README.md +138 -0
- package/dist/scaffold-repo/sdks/csharp/proto/blok/runtime/v1/runtime.proto +302 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Blok.Core.csproj +39 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Config/ServerConfig.cs +90 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/BlokError.cs +538 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/BlokErrorCategory.cs +112 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/BlokErrorSeverity.cs +40 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/BuildContextSnapshot.cs +168 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/ErrorCategory.cs +13 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/NodeException.cs +44 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Logging/LogEntry.cs +34 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Logging/LogLevel.cs +12 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Logging/Logger.cs +92 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Middleware/IMiddleware.cs +14 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Middleware/LoggingMiddleware.cs +46 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Middleware/MiddlewareChain.cs +35 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Middleware/RecoveryMiddleware.cs +63 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Node/INodeHandler.cs +17 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Node/NodeRegistry.cs +128 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Node/TypedNode.cs +140 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/ApiCallNode.cs +129 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/BlokErrorDemoNode.cs +125 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/ChainTestNode.cs +79 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/HelloWorldNode.cs +45 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/TransformDataNode.cs +119 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/TypedGreetNode.cs +23 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Program.cs +26 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Server/BlokNodeRuntimeService.cs +536 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Server/RuntimeServer.cs +183 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Testing/MockContextBuilder.cs +117 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Testing/TestNodeRunner.cs +50 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/Context.cs +56 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/ExecutionMetrics.cs +21 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/ExecutionRequest.cs +15 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/ExecutionResult.cs +104 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/HealthStatus.cs +18 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/NodeConfig.cs +59 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/Request.cs +57 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/Response.cs +24 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/UserNodeRegistry.cs +17 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Validation/SchemaValidator.cs +198 -0
- package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Blok.Core.Tests.csproj +25 -0
- package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Errors/BlokErrorTests.cs +458 -0
- package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Logging/LoggerTests.cs +129 -0
- package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Node/NodeRegistryTests.cs +145 -0
- package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Testing/MockContextTests.cs +153 -0
- package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/TypedNodeTests.cs +69 -0
- package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Types/ExecutionResultTests.cs +110 -0
- package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Validation/SchemaValidatorTests.cs +233 -0
- package/dist/scaffold-repo/sdks/go/Dockerfile +33 -0
- package/dist/scaffold-repo/sdks/go/README.md +255 -0
- package/dist/scaffold-repo/sdks/go/blok_error.go +803 -0
- package/dist/scaffold-repo/sdks/go/blok_error_test.go +433 -0
- package/dist/scaffold-repo/sdks/go/cmd/server/main.go +45 -0
- package/dist/scaffold-repo/sdks/go/cmd/server/register_user_nodes.go +12 -0
- package/dist/scaffold-repo/sdks/go/config.go +157 -0
- package/dist/scaffold-repo/sdks/go/config_test.go +129 -0
- package/dist/scaffold-repo/sdks/go/define_node.go +87 -0
- package/dist/scaffold-repo/sdks/go/define_node_test.go +75 -0
- package/dist/scaffold-repo/sdks/go/errors.go +104 -0
- package/dist/scaffold-repo/sdks/go/errors_test.go +95 -0
- package/dist/scaffold-repo/sdks/go/examples/nodes/apicall.go +117 -0
- package/dist/scaffold-repo/sdks/go/examples/nodes/blokerrordemo.go +80 -0
- package/dist/scaffold-repo/sdks/go/examples/nodes/chaintest.go +63 -0
- package/dist/scaffold-repo/sdks/go/examples/nodes/helloworld.go +41 -0
- package/dist/scaffold-repo/sdks/go/examples/nodes/transformdata.go +176 -0
- package/dist/scaffold-repo/sdks/go/examples/nodes/typedgreet.go +34 -0
- package/dist/scaffold-repo/sdks/go/genpb/blok/runtime/v1/runtime.pb.go +2070 -0
- package/dist/scaffold-repo/sdks/go/genpb/blok/runtime/v1/runtime_grpc.pb.go +273 -0
- package/dist/scaffold-repo/sdks/go/go.mod +25 -0
- package/dist/scaffold-repo/sdks/go/go.sum +66 -0
- package/dist/scaffold-repo/sdks/go/grpc_server.go +670 -0
- package/dist/scaffold-repo/sdks/go/grpc_server_test.go +474 -0
- package/dist/scaffold-repo/sdks/go/logging.go +144 -0
- package/dist/scaffold-repo/sdks/go/logging_test.go +139 -0
- package/dist/scaffold-repo/sdks/go/middleware.go +152 -0
- package/dist/scaffold-repo/sdks/go/middleware_test.go +222 -0
- package/dist/scaffold-repo/sdks/go/node.go +50 -0
- package/dist/scaffold-repo/sdks/go/proto/blok/runtime/v1/runtime.proto +302 -0
- package/dist/scaffold-repo/sdks/go/registry.go +156 -0
- package/dist/scaffold-repo/sdks/go/registry_test.go +195 -0
- package/dist/scaffold-repo/sdks/go/server.go +207 -0
- package/dist/scaffold-repo/sdks/go/server_test.go +186 -0
- package/dist/scaffold-repo/sdks/go/shutdown.go +32 -0
- package/dist/scaffold-repo/sdks/go/testutil.go +169 -0
- package/dist/scaffold-repo/sdks/go/testutil_test.go +124 -0
- package/dist/scaffold-repo/sdks/go/types.go +295 -0
- package/dist/scaffold-repo/sdks/go/types_test.go +251 -0
- package/dist/scaffold-repo/sdks/go/validation.go +210 -0
- package/dist/scaffold-repo/sdks/go/validation_test.go +262 -0
- package/dist/scaffold-repo/sdks/go/worker.go +577 -0
- package/dist/scaffold-repo/sdks/java/Dockerfile +33 -0
- package/dist/scaffold-repo/sdks/java/README.md +221 -0
- package/dist/scaffold-repo/sdks/java/pom.xml +163 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/Main.java +90 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/UserNodeRegistry.java +19 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/config/ServerConfig.java +244 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/BlokError.java +576 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/BlokErrorCategory.java +68 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/BlokErrorSeverity.java +31 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/BuildContextSnapshot.java +132 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/ErrorCategory.java +22 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/NodeException.java +176 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/logging/LogEntry.java +78 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/logging/LogLevel.java +48 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/logging/Logger.java +160 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/middleware/LoggingMiddleware.java +65 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/middleware/Middleware.java +29 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/middleware/MiddlewareChain.java +59 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/middleware/RecoveryMiddleware.java +53 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/node/NodeHandler.java +40 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/node/NodeReflector.java +18 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/node/NodeRegistry.java +205 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/node/TypedNode.java +143 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/ApiCallNode.java +145 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/BlokErrorDemoNode.java +109 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/ChainTestNode.java +65 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/HelloWorldNode.java +62 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/TransformDataNode.java +121 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/TypedGreetNode.java +41 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/server/BlokGrpcServer.java +103 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/server/BlokNodeRuntimeService.java +501 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/server/RuntimeServer.java +176 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/testing/MockContext.java +120 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/testing/TestRunner.java +59 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/Context.java +167 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/ExecutionMetrics.java +80 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/ExecutionRequest.java +61 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/ExecutionResult.java +188 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/HealthStatus.java +77 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/NodeConfig.java +139 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/Request.java +154 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/Response.java +77 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/validation/SchemaValidator.java +178 -0
- package/dist/scaffold-repo/sdks/java/src/main/proto/blok/runtime/v1/runtime.proto +302 -0
- package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/errors/BlokErrorTest.java +416 -0
- package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/logging/LoggerTest.java +176 -0
- package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/node/NodeRegistryTest.java +227 -0
- package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/node/TypedNodeTest.java +76 -0
- package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/server/RuntimeServerTest.java +197 -0
- package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/types/ExecutionResultTest.java +194 -0
- package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/validation/SchemaValidatorTest.java +246 -0
- package/dist/scaffold-repo/sdks/php/.rr.yaml +29 -0
- package/dist/scaffold-repo/sdks/php/Dockerfile +61 -0
- package/dist/scaffold-repo/sdks/php/README.md +387 -0
- package/dist/scaffold-repo/sdks/php/composer.json +41 -0
- package/dist/scaffold-repo/sdks/php/examples/ApiCallNode.php +103 -0
- package/dist/scaffold-repo/sdks/php/examples/BlokErrorDemoNode.php +90 -0
- package/dist/scaffold-repo/sdks/php/examples/ChainTestNode.php +56 -0
- package/dist/scaffold-repo/sdks/php/examples/HelloWorldNode.php +39 -0
- package/dist/scaffold-repo/sdks/php/examples/TransformDataNode.php +94 -0
- package/dist/scaffold-repo/sdks/php/examples/TypedGreetNode.php +57 -0
- package/dist/scaffold-repo/sdks/php/phpunit.xml +23 -0
- package/dist/scaffold-repo/sdks/php/proto/blok/runtime/v1/runtime.proto +302 -0
- package/dist/scaffold-repo/sdks/php/src/Config/ServerConfig.php +83 -0
- package/dist/scaffold-repo/sdks/php/src/Errors/BlokError.php +467 -0
- package/dist/scaffold-repo/sdks/php/src/Errors/BlokErrorBuilder.php +121 -0
- package/dist/scaffold-repo/sdks/php/src/Errors/BlokErrorCategory.php +83 -0
- package/dist/scaffold-repo/sdks/php/src/Errors/BlokErrorSeverity.php +30 -0
- package/dist/scaffold-repo/sdks/php/src/Errors/BuildContextSnapshot.php +141 -0
- package/dist/scaffold-repo/sdks/php/src/Errors/ErrorCategory.php +17 -0
- package/dist/scaffold-repo/sdks/php/src/Errors/NodeException.php +107 -0
- package/dist/scaffold-repo/sdks/php/src/Errors/Origin.php +35 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ErrorCategory.php +118 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ErrorSeverity.php +72 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ExecuteEvent.php +181 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ExecuteOptions.php +159 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ExecuteRequest.php +328 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ExecuteResponse.php +288 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/HealthRequest.php +59 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/HealthResponse/Status.php +54 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/HealthResponse.php +113 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ListNodesRequest.php +32 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ListNodesResponse.php +154 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/LogLine.php +156 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/Metrics.php +165 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeDescriptor.php +174 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeError.php +627 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeRef.php +134 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeRuntimeClient.php +101 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeStarted.php +68 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/PartialResult.php +59 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/Progress.php +85 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/RuntimeState.php +142 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/StepInfo.php +168 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/TriggerInfo.php +289 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/WorkflowInfo.php +176 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/GPBMetadata/Blok/Runtime/V1/Runtime.php +26 -0
- package/dist/scaffold-repo/sdks/php/src/Logging/LogEntry.php +47 -0
- package/dist/scaffold-repo/sdks/php/src/Logging/LogLevel.php +50 -0
- package/dist/scaffold-repo/sdks/php/src/Logging/Logger.php +133 -0
- package/dist/scaffold-repo/sdks/php/src/Node/NodeHandler.php +35 -0
- package/dist/scaffold-repo/sdks/php/src/Node/NodeReflector.php +21 -0
- package/dist/scaffold-repo/sdks/php/src/Node/NodeRegistry.php +172 -0
- package/dist/scaffold-repo/sdks/php/src/Node/TypedNode.php +159 -0
- package/dist/scaffold-repo/sdks/php/src/Server/BlokNodeRuntimeService.php +504 -0
- package/dist/scaffold-repo/sdks/php/src/Server/DecodeException.php +13 -0
- package/dist/scaffold-repo/sdks/php/src/Server/Middleware.php +18 -0
- package/dist/scaffold-repo/sdks/php/src/Server/MiddlewarePipeline.php +33 -0
- package/dist/scaffold-repo/sdks/php/src/Server/NodeRuntimeInterface.php +40 -0
- package/dist/scaffold-repo/sdks/php/src/Server/Server.php +157 -0
- package/dist/scaffold-repo/sdks/php/src/Testing/MockContext.php +161 -0
- package/dist/scaffold-repo/sdks/php/src/Testing/TestRunner.php +78 -0
- package/dist/scaffold-repo/sdks/php/src/Types/Context.php +80 -0
- package/dist/scaffold-repo/sdks/php/src/Types/ExecutionMetrics.php +48 -0
- package/dist/scaffold-repo/sdks/php/src/Types/ExecutionRequest.php +38 -0
- package/dist/scaffold-repo/sdks/php/src/Types/ExecutionResult.php +143 -0
- package/dist/scaffold-repo/sdks/php/src/Types/HealthStatus.php +42 -0
- package/dist/scaffold-repo/sdks/php/src/Types/NodeConfig.php +72 -0
- package/dist/scaffold-repo/sdks/php/src/Types/Request.php +82 -0
- package/dist/scaffold-repo/sdks/php/src/Types/Response.php +44 -0
- package/dist/scaffold-repo/sdks/php/src/Validation/SchemaValidator.php +197 -0
- package/dist/scaffold-repo/sdks/php/tests/Errors/BlokErrorTest.php +402 -0
- package/dist/scaffold-repo/sdks/php/tests/Logging/LoggerTest.php +165 -0
- package/dist/scaffold-repo/sdks/php/tests/Node/NodeRegistryTest.php +139 -0
- package/dist/scaffold-repo/sdks/php/tests/Node/TypedNodeTest.php +84 -0
- package/dist/scaffold-repo/sdks/php/tests/Server/BlokNodeRuntimeServiceTest.php +288 -0
- package/dist/scaffold-repo/sdks/php/tests/Testing/MockContextTest.php +184 -0
- package/dist/scaffold-repo/sdks/php/tests/Types/ExecutionResultTest.php +136 -0
- package/dist/scaffold-repo/sdks/php/tests/Validation/SchemaValidatorTest.php +191 -0
- package/dist/scaffold-repo/sdks/python3/Dockerfile +62 -0
- package/dist/scaffold-repo/sdks/python3/blok/__init__.py +61 -0
- package/dist/scaffold-repo/sdks/python3/blok/config/__init__.py +3 -0
- package/dist/scaffold-repo/sdks/python3/blok/config/server_config.py +116 -0
- package/dist/scaffold-repo/sdks/python3/blok/errors/__init__.py +50 -0
- package/dist/scaffold-repo/sdks/python3/blok/errors/blok_error.py +555 -0
- package/dist/scaffold-repo/sdks/python3/blok/errors/node_error.py +64 -0
- package/dist/scaffold-repo/sdks/python3/blok/logging/__init__.py +3 -0
- package/dist/scaffold-repo/sdks/python3/blok/logging/logger.py +82 -0
- package/dist/scaffold-repo/sdks/python3/blok/middleware/__init__.py +4 -0
- package/dist/scaffold-repo/sdks/python3/blok/middleware/logging_middleware.py +35 -0
- package/dist/scaffold-repo/sdks/python3/blok/middleware/recovery_middleware.py +36 -0
- package/dist/scaffold-repo/sdks/python3/blok/node/__init__.py +4 -0
- package/dist/scaffold-repo/sdks/python3/blok/node/define_node.py +239 -0
- package/dist/scaffold-repo/sdks/python3/blok/node/node_handler.py +35 -0
- package/dist/scaffold-repo/sdks/python3/blok/node/node_registry.py +136 -0
- package/dist/scaffold-repo/sdks/python3/blok/runtime/__init__.py +0 -0
- package/dist/scaffold-repo/sdks/python3/blok/runtime/v1/__init__.py +0 -0
- package/dist/scaffold-repo/sdks/python3/blok/runtime/v1/runtime_pb2.py +112 -0
- package/dist/scaffold-repo/sdks/python3/blok/runtime/v1/runtime_pb2_grpc.py +259 -0
- package/dist/scaffold-repo/sdks/python3/blok/server/__init__.py +3 -0
- package/dist/scaffold-repo/sdks/python3/blok/server/grpc_server.py +757 -0
- package/dist/scaffold-repo/sdks/python3/blok/server/runtime_server.py +165 -0
- package/dist/scaffold-repo/sdks/python3/blok/types/__init__.py +13 -0
- package/dist/scaffold-repo/sdks/python3/blok/types/context.py +162 -0
- package/dist/scaffold-repo/sdks/python3/blok/types/execution_request.py +74 -0
- package/dist/scaffold-repo/sdks/python3/blok/types/execution_result.py +103 -0
- package/dist/scaffold-repo/sdks/python3/blok/worker/__init__.py +10 -0
- package/dist/scaffold-repo/sdks/python3/blok/worker/job_message.py +34 -0
- package/dist/scaffold-repo/sdks/python3/blok/worker/worker.py +451 -0
- package/dist/scaffold-repo/sdks/python3/blok/worker/worker_config.py +129 -0
- package/dist/scaffold-repo/sdks/python3/examples/__init__.py +32 -0
- package/dist/scaffold-repo/sdks/python3/examples/api_call_node.py +85 -0
- package/dist/scaffold-repo/sdks/python3/examples/blok_error_demo_node.py +79 -0
- package/dist/scaffold-repo/sdks/python3/examples/chain_test_node.py +51 -0
- package/dist/scaffold-repo/sdks/python3/examples/hello_world_node.py +44 -0
- package/dist/scaffold-repo/sdks/python3/examples/transform_data_node.py +71 -0
- package/dist/scaffold-repo/sdks/python3/examples/typed_greet_node.py +25 -0
- package/dist/scaffold-repo/sdks/python3/proto/blok/runtime/v1/runtime.proto +302 -0
- package/dist/scaffold-repo/sdks/python3/pyproject.toml +47 -0
- package/dist/scaffold-repo/sdks/python3/requirements.txt +17 -0
- package/dist/scaffold-repo/sdks/python3/tests/__init__.py +0 -0
- package/dist/scaffold-repo/sdks/python3/tests/test_blok_error.py +341 -0
- package/dist/scaffold-repo/sdks/python3/tests/test_define_node.py +135 -0
- package/dist/scaffold-repo/sdks/python3/tests/test_discovery.py +99 -0
- package/dist/scaffold-repo/sdks/python3/tests/test_grpc_codec.py +260 -0
- package/dist/scaffold-repo/sdks/python3/tests/test_grpc_server.py +398 -0
- package/dist/scaffold-repo/sdks/ruby/Dockerfile +37 -0
- package/dist/scaffold-repo/sdks/ruby/Gemfile +5 -0
- package/dist/scaffold-repo/sdks/ruby/README.md +210 -0
- package/dist/scaffold-repo/sdks/ruby/Rakefile +11 -0
- package/dist/scaffold-repo/sdks/ruby/blok.gemspec +43 -0
- package/dist/scaffold-repo/sdks/ruby/config.ru +15 -0
- package/dist/scaffold-repo/sdks/ruby/examples/api_call_node.rb +99 -0
- package/dist/scaffold-repo/sdks/ruby/examples/blok_error_demo_node.rb +79 -0
- package/dist/scaffold-repo/sdks/ruby/examples/chain_test_node.rb +51 -0
- package/dist/scaffold-repo/sdks/ruby/examples/hello_world_node.rb +40 -0
- package/dist/scaffold-repo/sdks/ruby/examples/transform_data_node.rb +82 -0
- package/dist/scaffold-repo/sdks/ruby/examples/typed_greet_node.rb +25 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/config/server_config.rb +76 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/errors/blok_error.rb +476 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/errors/build_context_snapshot.rb +99 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/errors/error_category.rb +16 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/errors/node_error.rb +84 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/logging/log_entry.rb +46 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/logging/log_level.rb +49 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/logging/logger.rb +71 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/middleware/logging_middleware.rb +45 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/middleware/middleware.rb +36 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/middleware/recovery_middleware.rb +31 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/node/discovery.rb +59 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/node/node_handler.rb +43 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/node/node_registry.rb +107 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/node/typed_node.rb +180 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/runtime/v1/runtime_pb.rb +43 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/runtime/v1/runtime_services_pb.rb +55 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/server/grpc_server.rb +435 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/server/runtime_app.rb +86 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/testing/mock_context.rb +109 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/testing/test_runner.rb +40 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/types/context.rb +82 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/types/execution_metrics.rb +43 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/types/execution_request.rb +39 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/types/execution_result.rb +117 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/types/health_status.rb +42 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/types/node_config.rb +73 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/types/request.rb +71 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/types/response.rb +46 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/validation/schema_validator.rb +142 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/version.rb +5 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok.rb +53 -0
- package/dist/scaffold-repo/sdks/ruby/proto/blok/runtime/v1/runtime.proto +302 -0
- package/dist/scaffold-repo/sdks/ruby/test/errors/blok_error_test.rb +339 -0
- package/dist/scaffold-repo/sdks/ruby/test/logging/logger_test.rb +155 -0
- package/dist/scaffold-repo/sdks/ruby/test/node/node_registry_test.rb +132 -0
- package/dist/scaffold-repo/sdks/ruby/test/node/typed_node_test.rb +67 -0
- package/dist/scaffold-repo/sdks/ruby/test/test_helper.rb +6 -0
- package/dist/scaffold-repo/sdks/ruby/test/testing/mock_context_test.rb +150 -0
- package/dist/scaffold-repo/sdks/ruby/test/types/execution_result_test.rb +129 -0
- package/dist/scaffold-repo/sdks/ruby/test/validation/schema_validator_test.rb +270 -0
- package/dist/scaffold-repo/sdks/rust/Cargo.lock +3044 -0
- package/dist/scaffold-repo/sdks/rust/Cargo.toml +82 -0
- package/dist/scaffold-repo/sdks/rust/Dockerfile +40 -0
- package/dist/scaffold-repo/sdks/rust/README.md +73 -0
- package/dist/scaffold-repo/sdks/rust/build.rs +32 -0
- package/dist/scaffold-repo/sdks/rust/proto/blok/runtime/v1/runtime.proto +302 -0
- package/dist/scaffold-repo/sdks/rust/src/blok_error.rs +1168 -0
- package/dist/scaffold-repo/sdks/rust/src/config.rs +158 -0
- package/dist/scaffold-repo/sdks/rust/src/errors.rs +142 -0
- package/dist/scaffold-repo/sdks/rust/src/grpc_server.rs +635 -0
- package/dist/scaffold-repo/sdks/rust/src/lib.rs +65 -0
- package/dist/scaffold-repo/sdks/rust/src/logging.rs +195 -0
- package/dist/scaffold-repo/sdks/rust/src/main.rs +79 -0
- package/dist/scaffold-repo/sdks/rust/src/middleware.rs +181 -0
- package/dist/scaffold-repo/sdks/rust/src/node.rs +172 -0
- package/dist/scaffold-repo/sdks/rust/src/nodes/api_call.rs +93 -0
- package/dist/scaffold-repo/sdks/rust/src/nodes/blok_error_demo.rs +151 -0
- package/dist/scaffold-repo/sdks/rust/src/nodes/chain_test.rs +57 -0
- package/dist/scaffold-repo/sdks/rust/src/nodes/hello_world.rs +83 -0
- package/dist/scaffold-repo/sdks/rust/src/nodes/mod.rs +18 -0
- package/dist/scaffold-repo/sdks/rust/src/nodes/transform_data.rs +142 -0
- package/dist/scaffold-repo/sdks/rust/src/nodes/typed_greet.rs +56 -0
- package/dist/scaffold-repo/sdks/rust/src/registry.rs +204 -0
- package/dist/scaffold-repo/sdks/rust/src/server.rs +63 -0
- package/dist/scaffold-repo/sdks/rust/src/testing.rs +175 -0
- package/dist/scaffold-repo/sdks/rust/src/types.rs +338 -0
- package/dist/scaffold-repo/sdks/rust/src/user_nodes/mod.rs +10 -0
- package/dist/scaffold-repo/sdks/rust/src/validation.rs +232 -0
- package/dist/scaffold-repo/sdks/rust/src/worker.rs +509 -0
- package/dist/scaffold-repo/sdks/rust/tests/grpc_integration.rs +306 -0
- package/dist/scaffold-repo/sdks/rust/tests/typed_node.rs +104 -0
- package/dist/scaffold-repo/triggers/cron/CHANGELOG.md +22 -0
- package/dist/scaffold-repo/triggers/cron/package.json +36 -0
- package/dist/scaffold-repo/triggers/cron/src/CronTrigger.ts +552 -0
- package/dist/scaffold-repo/triggers/cron/src/index.ts +77 -0
- package/dist/scaffold-repo/triggers/cron/tsconfig.json +32 -0
- package/dist/scaffold-repo/triggers/grpc/.env.example +8 -0
- package/dist/scaffold-repo/triggers/grpc/CHANGELOG.md +143 -0
- package/dist/scaffold-repo/triggers/grpc/README.md +25 -0
- package/dist/scaffold-repo/triggers/grpc/buf.gen.yaml +11 -0
- package/dist/scaffold-repo/triggers/grpc/buf.yaml +9 -0
- package/dist/scaffold-repo/triggers/grpc/localhost+2-key.pem +28 -0
- package/dist/scaffold-repo/triggers/grpc/localhost+2.pem +27 -0
- package/dist/scaffold-repo/triggers/grpc/package.json +61 -0
- package/dist/scaffold-repo/triggers/grpc/proto/workflow.proto +33 -0
- package/dist/scaffold-repo/triggers/grpc/src/GRpcTrigger.ts +297 -0
- package/dist/scaffold-repo/triggers/grpc/src/GrpcClient.ts +87 -0
- package/dist/scaffold-repo/triggers/grpc/src/GrpcServer.ts +68 -0
- package/dist/scaffold-repo/triggers/grpc/src/MessageDecode.ts +142 -0
- package/dist/scaffold-repo/triggers/grpc/src/NanoSDK.ts +146 -0
- package/dist/scaffold-repo/triggers/grpc/src/Nodes.ts +10 -0
- package/dist/scaffold-repo/triggers/grpc/src/Workflows.ts +5 -0
- package/dist/scaffold-repo/triggers/grpc/src/gen/workflow_pb.ts +142 -0
- package/dist/scaffold-repo/triggers/grpc/src/index.ts +22 -0
- package/dist/scaffold-repo/triggers/grpc/src/server.ts +8 -0
- package/dist/scaffold-repo/triggers/grpc/src/types/Message.ts +0 -0
- package/dist/scaffold-repo/triggers/grpc/src/types/RuntimeWorkflow.ts +7 -0
- package/dist/scaffold-repo/triggers/grpc/src/types/Workflows.ts +7 -0
- package/dist/scaffold-repo/triggers/grpc/tsconfig.json +34 -0
- package/dist/scaffold-repo/triggers/grpc/vitest.config.ts +29 -0
- package/dist/scaffold-repo/triggers/grpc/workflows/countries.json +27 -0
- package/dist/scaffold-repo/triggers/http/.blok/trace.db +0 -0
- package/dist/scaffold-repo/triggers/http/.blok/trace.db-shm +0 -0
- package/dist/scaffold-repo/triggers/http/.blok/trace.db-wal +0 -0
- package/dist/scaffold-repo/triggers/http/.dockerignore +23 -0
- package/dist/scaffold-repo/triggers/http/.env.example +8 -0
- package/dist/scaffold-repo/triggers/http/CHANGELOG.md +326 -0
- package/dist/scaffold-repo/triggers/http/Dockerfile +49 -0
- package/dist/scaffold-repo/triggers/http/Dockerfile.dev +34 -0
- package/dist/scaffold-repo/triggers/http/infra/docker-compose.yml +38 -0
- package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Authentication.md +74 -0
- package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Building.md +52 -0
- package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Create_Node.md +123 -0
- package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Create_Workflow.md +177 -0
- package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Deployment.md +69 -0
- package/dist/scaffold-repo/triggers/http/notes/Core_Concepts/Context.md +156 -0
- package/dist/scaffold-repo/triggers/http/notes/examples.md +104 -0
- package/dist/scaffold-repo/triggers/http/notes/index.md +51 -0
- package/dist/scaffold-repo/triggers/http/package.json +62 -0
- package/dist/scaffold-repo/triggers/http/public/favicon.ico +0 -0
- package/dist/scaffold-repo/triggers/http/public/metric/index.html +2101 -0
- package/dist/scaffold-repo/triggers/http/request.http +7 -0
- package/dist/scaffold-repo/triggers/http/src/AppRoutes.ts +64 -0
- package/dist/scaffold-repo/triggers/http/src/Nodes.ts +38 -0
- package/dist/scaffold-repo/triggers/http/src/Workflows.ts +18 -0
- package/dist/scaffold-repo/triggers/http/src/index.ts +86 -0
- package/dist/scaffold-repo/triggers/http/src/nodes/chain-init/index.ts +48 -0
- package/dist/scaffold-repo/triggers/http/src/nodes/chain-verify/index.ts +123 -0
- package/dist/scaffold-repo/triggers/http/src/nodes/eval/index.ts +69 -0
- package/dist/scaffold-repo/triggers/http/src/nodes/examples/README.md +14 -0
- package/dist/scaffold-repo/triggers/http/src/nodes/examples/chat-ui/index.html +228 -0
- package/dist/scaffold-repo/triggers/http/src/nodes/examples/chat-ui/index.ts +65 -0
- package/dist/scaffold-repo/triggers/http/src/nodes/examples/index.ts +14 -0
- package/dist/scaffold-repo/triggers/http/src/nodes/runtime-bridge/index.ts +84 -0
- package/dist/scaffold-repo/triggers/http/src/runner/HonoTraceRouterAdapter.ts +199 -0
- package/dist/scaffold-repo/triggers/http/src/runner/HttpTrigger.ts +2039 -0
- package/dist/scaffold-repo/triggers/http/src/runner/MessageDecode.ts +57 -0
- package/dist/scaffold-repo/triggers/http/src/runner/Util.ts +52 -0
- package/dist/scaffold-repo/triggers/http/src/runner/WorkflowRouter.ts +411 -0
- package/dist/scaffold-repo/triggers/http/src/runner/metrics/opentelemetry_metrics.ts +84 -0
- package/dist/scaffold-repo/triggers/http/src/runner/metrics/opentelemetry_traces.ts +30 -0
- package/dist/scaffold-repo/triggers/http/src/runner/nodeCatalog.ts +128 -0
- package/dist/scaffold-repo/triggers/http/src/runner/responseEmitter.ts +138 -0
- package/dist/scaffold-repo/triggers/http/src/runner/scanWorkflows.ts +201 -0
- package/dist/scaffold-repo/triggers/http/src/runner/types/ErrorResponse.ts +3 -0
- package/dist/scaffold-repo/triggers/http/src/runner/types/NodeTypes.ts +13 -0
- package/dist/scaffold-repo/triggers/http/src/runner/types/Nodes.ts +5 -0
- package/dist/scaffold-repo/triggers/http/src/runner/types/RuntimeWorkflow.ts +7 -0
- package/dist/scaffold-repo/triggers/http/src/runner/types/WorkflowRequest.ts +8 -0
- package/dist/scaffold-repo/triggers/http/src/runner/types/WorkflowResponse.ts +7 -0
- package/dist/scaffold-repo/triggers/http/src/runner/types/Workflows.ts +14 -0
- package/dist/scaffold-repo/triggers/http/src/workflows/countries-cats-helper.ts +30 -0
- package/dist/scaffold-repo/triggers/http/src/workflows/countries-handle-dsl.ts +25 -0
- package/dist/scaffold-repo/triggers/http/src/workflows/countries-helper.ts +18 -0
- package/dist/scaffold-repo/triggers/http/src/workflows/empty.ts +16 -0
- package/dist/scaffold-repo/triggers/http/src/workflows/eval/eval-retrieve.ts +23 -0
- package/dist/scaffold-repo/triggers/http/src/workflows/eval/eval-run.ts +39 -0
- package/dist/scaffold-repo/triggers/http/src/workflows/eval/foreign-auth.ts +24 -0
- package/dist/scaffold-repo/triggers/http/tsconfig.json +39 -0
- package/dist/scaffold-repo/triggers/http/vitest.config.ts +39 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/agent-message.json +87 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/agent-page.json +25 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/agent-stream.json +30 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/agent-tool-calculator.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/agent-tool-weather.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/chat-memory-message.json +54 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/chat-memory-page.json +25 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/chat-memory-stream.json +30 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/chat-message.json +25 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/chat-page.json +20 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/chat-stream.json +30 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/countries-py.json +27 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/countries-vs-facts.json +50 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/countries.json +27 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/cross-runtime-chain.json +89 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/dashboard-gen.json +34 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/db-manager.json +34 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/empty.json +13 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/fanout-enqueue.json +48 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/fanout-worker.json +41 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/feedback.json +34 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/films.json +27 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/image-capture.json +34 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/launches-by-year.json +27 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/loadtest.json +24 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/middleware/admin-only.json +31 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/middleware/auth-check.json +59 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/middleware/github-webhook-verify.json +34 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/middleware/jwt-auth.json +46 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/middleware/rate-limit.json +70 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/middleware/redis-rate-limit.json +71 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/mongodb.json +24 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/rentals-pdf.json +65 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-admin-delete-user.json +42 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-async-job-poller.json +45 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-csv-import.json +122 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-data-export.json +105 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-event-router.json +97 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-github-handler-issues.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-github-handler-pr.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-github-handler-push.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-github-webhook-router.json +88 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-hello-global-mw.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-hello-with-mw.json +23 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-jwt-protected.json +23 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-multi-tenant-router.json +90 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-nested-control-flow.json +207 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-order-fulfillment.json +211 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-parallel-foreach-with-wait.json +47 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-polling-with-backoff.json +55 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-protected.json +23 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-redis-protected.json +23 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-saga.json +122 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-tenant-acme.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-tenant-beta.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-tenant-gamma.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-travel-booking.json +200 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-user-signup-saga.json +186 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-webhook-fanout.json +49 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v06-reliability-showcase.json +80 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v07-sse-publish.json +24 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v07-sse-stream.json +26 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v07-ws-echo.json +38 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-github-issues.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-github-pr.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-github-push.json +32 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-github.json +87 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-linear-comment.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-linear-issue.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-linear.json +74 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-stripe-customer-created.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-stripe-invoice-paid.json +32 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-stripe.json +24 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/workflow-docs.json +34 -0
- package/dist/scaffold-repo/triggers/http/workflows/toml/countries.toml +21 -0
- package/dist/scaffold-repo/triggers/http/workflows/xml/countries.xml +23 -0
- package/dist/scaffold-repo/triggers/http/workflows/yaml/countries.yaml +19 -0
- package/dist/scaffold-repo/triggers/mcp/README.md +131 -0
- package/dist/scaffold-repo/triggers/mcp/package.json +39 -0
- package/dist/scaffold-repo/triggers/mcp/src/McpTrigger.ts +581 -0
- package/dist/scaffold-repo/triggers/mcp/src/index.ts +41 -0
- package/dist/scaffold-repo/triggers/mcp/tsconfig.json +32 -0
- package/dist/scaffold-repo/triggers/pubsub/CHANGELOG.md +22 -0
- package/dist/scaffold-repo/triggers/pubsub/package.json +66 -0
- package/dist/scaffold-repo/triggers/pubsub/src/PubSubTrigger.ts +424 -0
- package/dist/scaffold-repo/triggers/pubsub/src/adapters/AWSSNSAdapter.ts +352 -0
- package/dist/scaffold-repo/triggers/pubsub/src/adapters/AzureServiceBusAdapter.ts +303 -0
- package/dist/scaffold-repo/triggers/pubsub/src/adapters/GCPPubSubAdapter.ts +327 -0
- package/dist/scaffold-repo/triggers/pubsub/src/adapters/KafkaPubSubAdapter.ts +247 -0
- package/dist/scaffold-repo/triggers/pubsub/src/adapters/KafkaPubSubAdapter.ts.bak +251 -0
- package/dist/scaffold-repo/triggers/pubsub/src/adapters/NATSPubSubAdapter.ts +333 -0
- package/dist/scaffold-repo/triggers/pubsub/src/adapters/RedisStreamsPubSubAdapter.ts +256 -0
- package/dist/scaffold-repo/triggers/pubsub/src/adapters/factory.ts +88 -0
- package/dist/scaffold-repo/triggers/pubsub/src/index.ts +67 -0
- package/dist/scaffold-repo/triggers/pubsub/template/.env.example +8 -0
- package/dist/scaffold-repo/triggers/pubsub/template/package.json +45 -0
- package/dist/scaffold-repo/triggers/pubsub/template/src/Nodes.ts +20 -0
- package/dist/scaffold-repo/triggers/pubsub/template/src/Workflows.ts +8 -0
- package/dist/scaffold-repo/triggers/pubsub/template/src/index.ts +41 -0
- package/dist/scaffold-repo/triggers/pubsub/template/src/runner/PubSubServer.ts +39 -0
- package/dist/scaffold-repo/triggers/pubsub/template/src/runner/types/Workflows.ts +7 -0
- package/dist/scaffold-repo/triggers/pubsub/template/src/workflows/messages/on-message.ts +42 -0
- package/dist/scaffold-repo/triggers/pubsub/template/src/workflows/publish-order.ts +22 -0
- package/dist/scaffold-repo/triggers/pubsub/template/tsconfig.json +31 -0
- package/dist/scaffold-repo/triggers/pubsub/template/vitest.config.ts +39 -0
- package/dist/scaffold-repo/triggers/pubsub/tsconfig.json +32 -0
- package/dist/scaffold-repo/triggers/sse/.env.example +8 -0
- package/dist/scaffold-repo/triggers/sse/CHANGELOG.md +12 -0
- package/dist/scaffold-repo/triggers/sse/Dockerfile +47 -0
- package/dist/scaffold-repo/triggers/sse/Dockerfile.dev +33 -0
- package/dist/scaffold-repo/triggers/sse/package.json +37 -0
- package/dist/scaffold-repo/triggers/sse/src/SSETrigger.ts +489 -0
- package/dist/scaffold-repo/triggers/sse/src/bus.ts +208 -0
- package/dist/scaffold-repo/triggers/sse/src/index.ts +38 -0
- package/dist/scaffold-repo/triggers/sse/src/workflows/events/README.md +129 -0
- package/dist/scaffold-repo/triggers/sse/src/workflows/events/publish-demo.ts +40 -0
- package/dist/scaffold-repo/triggers/sse/src/workflows/events/stream-demo.ts +43 -0
- package/dist/scaffold-repo/triggers/sse/tsconfig.json +22 -0
- package/dist/scaffold-repo/triggers/sse/vitest.config.ts +39 -0
- package/dist/scaffold-repo/triggers/webhook/CHANGELOG.md +22 -0
- package/dist/scaffold-repo/triggers/webhook/package.json +36 -0
- package/dist/scaffold-repo/triggers/webhook/src/WebhookTrigger.ts +465 -0
- package/dist/scaffold-repo/triggers/webhook/src/index.ts +51 -0
- package/dist/scaffold-repo/triggers/webhook/src/verifiers.ts +394 -0
- package/dist/scaffold-repo/triggers/webhook/tsconfig.json +32 -0
- package/dist/scaffold-repo/triggers/websocket/.env.example +8 -0
- package/dist/scaffold-repo/triggers/websocket/CHANGELOG.md +22 -0
- package/dist/scaffold-repo/triggers/websocket/package.json +50 -0
- package/dist/scaffold-repo/triggers/websocket/src/Backplane.ts +167 -0
- package/dist/scaffold-repo/triggers/websocket/src/WebSocketTrigger.ts +910 -0
- package/dist/scaffold-repo/triggers/websocket/src/index.ts +50 -0
- package/dist/scaffold-repo/triggers/websocket/src/workflows/events/README.md +93 -0
- package/dist/scaffold-repo/triggers/websocket/src/workflows/events/echo-demo.ts +56 -0
- package/dist/scaffold-repo/triggers/websocket/tsconfig.json +22 -0
- package/dist/scaffold-repo/triggers/websocket/vitest.config.ts +39 -0
- package/dist/scaffold-repo/triggers/worker/CHANGELOG.md +22 -0
- package/dist/scaffold-repo/triggers/worker/package.json +68 -0
- package/dist/scaffold-repo/triggers/worker/src/WorkerTrigger.ts +943 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/BullMQAdapter.ts +296 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/InMemoryAdapter.ts +280 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/KafkaAdapter.ts +347 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/NATSAdapter.ts +505 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/PgBossAdapter.ts +319 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/RabbitMQAdapter.ts +318 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/RedisStreamsAdapter.ts +513 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/SQSAdapter.ts +314 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/factory.ts +111 -0
- package/dist/scaffold-repo/triggers/worker/src/index.ts +95 -0
- package/dist/scaffold-repo/triggers/worker/template/.env.example +18 -0
- package/dist/scaffold-repo/triggers/worker/template/package.json +46 -0
- package/dist/scaffold-repo/triggers/worker/template/src/Nodes.ts +20 -0
- package/dist/scaffold-repo/triggers/worker/template/src/Workflows.ts +8 -0
- package/dist/scaffold-repo/triggers/worker/template/src/index.ts +41 -0
- package/dist/scaffold-repo/triggers/worker/template/src/runner/WorkerServer.ts +34 -0
- package/dist/scaffold-repo/triggers/worker/template/src/runner/types/Workflows.ts +7 -0
- package/dist/scaffold-repo/triggers/worker/template/src/workflows/jobs/process-job.ts +40 -0
- package/dist/scaffold-repo/triggers/worker/template/tsconfig.json +31 -0
- package/dist/scaffold-repo/triggers/worker/template/vitest.config.ts +39 -0
- package/dist/scaffold-repo/triggers/worker/tsconfig.json +32 -0
- package/dist/scaffold-repo/workflows/json/agent-message.json +87 -0
- package/dist/scaffold-repo/workflows/json/agent-page.json +25 -0
- package/dist/scaffold-repo/workflows/json/agent-stream.json +30 -0
- package/dist/scaffold-repo/workflows/json/agent-tool-calculator.json +22 -0
- package/dist/scaffold-repo/workflows/json/agent-tool-weather.json +22 -0
- package/dist/scaffold-repo/workflows/json/chat-memory-message.json +54 -0
- package/dist/scaffold-repo/workflows/json/chat-memory-page.json +25 -0
- package/dist/scaffold-repo/workflows/json/chat-memory-stream.json +30 -0
- package/dist/scaffold-repo/workflows/json/chat-message.json +25 -0
- package/dist/scaffold-repo/workflows/json/chat-page.json +20 -0
- package/dist/scaffold-repo/workflows/json/chat-stream.json +30 -0
- package/dist/scaffold-repo/workflows/json/countries-vs-facts.json +50 -0
- package/dist/scaffold-repo/workflows/json/countries.json +27 -0
- package/dist/scaffold-repo/workflows/json/cron-heartbeat.json +15 -0
- package/dist/scaffold-repo/workflows/json/fanout-enqueue.json +48 -0
- package/dist/scaffold-repo/workflows/json/fanout-worker.json +41 -0
- package/dist/scaffold-repo/workflows/json/pubsub-on-order.json +24 -0
- package/dist/scaffold-repo/workflows/json/webhook-github-issues.json +22 -0
- package/dist/scaffold-repo/workflows/json/webhook-github-pr.json +22 -0
- package/dist/scaffold-repo/workflows/json/webhook-github-push.json +32 -0
- package/dist/scaffold-repo/workflows/json/webhook-github.json +87 -0
- package/dist/scaffold-repo/workflows/json/webhook-linear-comment.json +22 -0
- package/dist/scaffold-repo/workflows/json/webhook-linear-issue.json +22 -0
- package/dist/scaffold-repo/workflows/json/webhook-linear.json +74 -0
- package/dist/scaffold-repo/workflows/json/webhook-stripe-customer-created.json +22 -0
- package/dist/scaffold-repo/workflows/json/webhook-stripe-invoice-paid.json +32 -0
- package/dist/scaffold-repo/workflows/json/webhook-stripe.json +24 -0
- package/dist/services/runtime-detector.d.ts +2 -0
- package/dist/services/runtime-detector.js +35 -11
- package/dist/services/runtime-setup.d.ts +1 -0
- package/dist/services/runtime-setup.js +17 -7
- package/package.json +4 -4
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
"""Unit tests for the gRPC codec helpers in ``blok.server.grpc_server``.
|
|
2
|
+
|
|
3
|
+
Covers proto ↔ internal-type round-trips, edge cases (empty bytes,
|
|
4
|
+
malformed JSON, content-type sensitivity), and the structured-error
|
|
5
|
+
synthesis path.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
|
|
13
|
+
from blok.runtime.v1 import runtime_pb2 as pb
|
|
14
|
+
from blok.server.grpc_server import (
|
|
15
|
+
_decode_execute_request,
|
|
16
|
+
_decode_json_object,
|
|
17
|
+
_decode_json_value,
|
|
18
|
+
_decode_request_body,
|
|
19
|
+
_DecodeError,
|
|
20
|
+
_encode_execute_response,
|
|
21
|
+
_encode_json_bytes,
|
|
22
|
+
_internal_error_to_proto,
|
|
23
|
+
)
|
|
24
|
+
from blok.types.execution_result import ExecutionMetrics, ExecutionResult
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# =============================================================================
|
|
28
|
+
# JSON-bytes helpers
|
|
29
|
+
# =============================================================================
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TestJsonBytesHelpers:
|
|
33
|
+
def test_round_trip_objects_arrays_primitives(self):
|
|
34
|
+
for sample in [
|
|
35
|
+
{"a": 1, "b": "two", "c": [3, 4, 5]},
|
|
36
|
+
[1, 2, 3],
|
|
37
|
+
"plain string",
|
|
38
|
+
42,
|
|
39
|
+
True,
|
|
40
|
+
None,
|
|
41
|
+
]:
|
|
42
|
+
blob = _encode_json_bytes(sample)
|
|
43
|
+
decoded = _decode_json_value(blob, "field") if sample is not None else None
|
|
44
|
+
if sample is not None:
|
|
45
|
+
assert decoded == sample
|
|
46
|
+
|
|
47
|
+
def test_encode_empty_for_unencodable(self):
|
|
48
|
+
# Sets aren't JSON-encodable; helper falls back to empty bytes.
|
|
49
|
+
assert _encode_json_bytes({1, 2, 3}) == b""
|
|
50
|
+
|
|
51
|
+
def test_decode_empty_bytes_returns_default(self):
|
|
52
|
+
assert _decode_json_object(b"", "x") == {}
|
|
53
|
+
assert _decode_json_value(b"", "x") is None
|
|
54
|
+
|
|
55
|
+
def test_decode_object_wraps_non_object_payloads(self):
|
|
56
|
+
result = _decode_json_object(b"[1,2,3]", "inputs")
|
|
57
|
+
assert result == {"_value": [1, 2, 3]}
|
|
58
|
+
|
|
59
|
+
def test_decode_object_raises_on_malformed_json(self):
|
|
60
|
+
with pytest.raises(_DecodeError):
|
|
61
|
+
_decode_json_object(b"not json", "inputs")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# =============================================================================
|
|
65
|
+
# Request body decoding
|
|
66
|
+
# =============================================================================
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class TestRequestBodyDecoding:
|
|
70
|
+
def test_returns_none_for_empty_bytes(self):
|
|
71
|
+
assert _decode_request_body(b"", {}) is None
|
|
72
|
+
|
|
73
|
+
def test_parses_json_when_content_type_says_so(self):
|
|
74
|
+
body = _decode_request_body(
|
|
75
|
+
b'{"hello":"world"}',
|
|
76
|
+
{"content-type": "application/json"},
|
|
77
|
+
)
|
|
78
|
+
assert body == {"hello": "world"}
|
|
79
|
+
|
|
80
|
+
def test_falls_back_to_raw_string_for_other_content_types(self):
|
|
81
|
+
body = _decode_request_body(b"plain text", {"content-type": "text/plain"})
|
|
82
|
+
assert body == "plain text"
|
|
83
|
+
|
|
84
|
+
def test_falls_back_to_raw_string_when_json_is_malformed(self):
|
|
85
|
+
body = _decode_request_body(
|
|
86
|
+
b"not valid json",
|
|
87
|
+
{"content-type": "application/json"},
|
|
88
|
+
)
|
|
89
|
+
assert body == "not valid json"
|
|
90
|
+
|
|
91
|
+
def test_handles_capitalized_content_type_header(self):
|
|
92
|
+
body = _decode_request_body(b'"x"', {"Content-Type": "application/json"})
|
|
93
|
+
assert body == "x"
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# =============================================================================
|
|
97
|
+
# Execute request decoding
|
|
98
|
+
# =============================================================================
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _make_proto_request(*, node_name="store-tutorial", inputs=None, body_bytes=b""):
|
|
102
|
+
return pb.ExecuteRequest(
|
|
103
|
+
node=pb.NodeRef(name=node_name, type="runtime.python3", version=""),
|
|
104
|
+
inputs=_encode_json_bytes(inputs or {"foo": "bar"}),
|
|
105
|
+
step=pb.StepInfo(name=node_name, index=0, total=1, depth=0),
|
|
106
|
+
trigger=pb.TriggerInfo(
|
|
107
|
+
body=body_bytes,
|
|
108
|
+
headers={"content-type": "application/json"},
|
|
109
|
+
params={"id": "42"},
|
|
110
|
+
query={"foo": "bar"},
|
|
111
|
+
cookies={},
|
|
112
|
+
method="POST",
|
|
113
|
+
url="/",
|
|
114
|
+
base_url="",
|
|
115
|
+
trigger_kind="http",
|
|
116
|
+
),
|
|
117
|
+
state=pb.RuntimeState(
|
|
118
|
+
previous_output=_encode_json_bytes({"prev": True}),
|
|
119
|
+
vars=_encode_json_bytes({"counter": 1}),
|
|
120
|
+
env={"NODE_ENV": "test"},
|
|
121
|
+
),
|
|
122
|
+
workflow=pb.WorkflowInfo(
|
|
123
|
+
run_id="run_xyz",
|
|
124
|
+
name="wf",
|
|
125
|
+
path="/wf",
|
|
126
|
+
version="1.0.0",
|
|
127
|
+
started_at=None,
|
|
128
|
+
),
|
|
129
|
+
options=pb.ExecuteOptions(
|
|
130
|
+
deadline_ms=5000,
|
|
131
|
+
stream_logs=False,
|
|
132
|
+
capture_metrics=True,
|
|
133
|
+
hints={},
|
|
134
|
+
),
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class TestDecodeExecuteRequest:
|
|
139
|
+
def test_inputs_arrive_unwrapped(self):
|
|
140
|
+
req = _make_proto_request(inputs={"prefix": "Hi"})
|
|
141
|
+
decoded = _decode_execute_request(req)
|
|
142
|
+
# Closes BLOK_FRAMEWORK_FIXES.md #3 at the wire layer for Python.
|
|
143
|
+
assert decoded.node.config == {"prefix": "Hi"}
|
|
144
|
+
|
|
145
|
+
def test_node_identification_round_trips(self):
|
|
146
|
+
req = _make_proto_request(node_name="custom-node")
|
|
147
|
+
decoded = _decode_execute_request(req)
|
|
148
|
+
assert decoded.node.name == "custom-node"
|
|
149
|
+
assert decoded.node.type == "runtime.python3"
|
|
150
|
+
|
|
151
|
+
def test_workflow_metadata_populates_context(self):
|
|
152
|
+
req = _make_proto_request()
|
|
153
|
+
decoded = _decode_execute_request(req)
|
|
154
|
+
assert decoded.context.id == "run_xyz"
|
|
155
|
+
assert decoded.context.workflow_name == "wf"
|
|
156
|
+
assert decoded.context.workflow_path == "/wf"
|
|
157
|
+
|
|
158
|
+
def test_state_populates_response_data_and_vars(self):
|
|
159
|
+
req = _make_proto_request()
|
|
160
|
+
decoded = _decode_execute_request(req)
|
|
161
|
+
assert decoded.context.response.data == {"prev": True}
|
|
162
|
+
assert decoded.context.vars == {"counter": 1}
|
|
163
|
+
assert decoded.context.env == {"NODE_ENV": "test"}
|
|
164
|
+
|
|
165
|
+
def test_request_metadata_round_trips(self):
|
|
166
|
+
req = _make_proto_request(body_bytes=_encode_json_bytes({"name": "Blok"}))
|
|
167
|
+
decoded = _decode_execute_request(req)
|
|
168
|
+
assert decoded.context.request.body == {"name": "Blok"}
|
|
169
|
+
assert decoded.context.request.params == {"id": "42"}
|
|
170
|
+
assert decoded.context.request.query == {"foo": "bar"}
|
|
171
|
+
assert decoded.context.request.method == "POST"
|
|
172
|
+
|
|
173
|
+
def test_rejects_request_without_node(self):
|
|
174
|
+
bad = pb.ExecuteRequest() # node field missing → name is empty string
|
|
175
|
+
with pytest.raises(_DecodeError):
|
|
176
|
+
_decode_execute_request(bad)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
# =============================================================================
|
|
180
|
+
# Execute response encoding
|
|
181
|
+
# =============================================================================
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class TestEncodeExecuteResponse:
|
|
185
|
+
def test_success_round_trips_data(self):
|
|
186
|
+
result = ExecutionResult.success_result({"message": "Hi, Blok!"})
|
|
187
|
+
result.with_metrics(ExecutionMetrics(duration_ms=12.5))
|
|
188
|
+
proto = _encode_execute_response(
|
|
189
|
+
result,
|
|
190
|
+
node_name="hello-world",
|
|
191
|
+
sdk_version="1.0.0",
|
|
192
|
+
)
|
|
193
|
+
assert proto.success is True
|
|
194
|
+
assert proto.error is None or proto.error.code == ""
|
|
195
|
+
assert json.loads(proto.data) == {"message": "Hi, Blok!"}
|
|
196
|
+
assert proto.metrics.duration_ms == pytest.approx(12.5)
|
|
197
|
+
|
|
198
|
+
def test_failure_populates_structured_node_error(self):
|
|
199
|
+
result = ExecutionResult.error_result("Postgres unreachable")
|
|
200
|
+
proto = _encode_execute_response(
|
|
201
|
+
result,
|
|
202
|
+
node_name="store-tutorial",
|
|
203
|
+
sdk_version="1.0.0",
|
|
204
|
+
)
|
|
205
|
+
assert proto.success is False
|
|
206
|
+
err = proto.error
|
|
207
|
+
# Per master plan §17.7, unstructured errors auto-categorize as
|
|
208
|
+
# INTERNAL with code=UNCAUGHT_ERROR (the original payload is
|
|
209
|
+
# preserved in details_json).
|
|
210
|
+
assert err.code == "UNCAUGHT_ERROR"
|
|
211
|
+
assert err.category == pb.ErrorCategory.INTERNAL
|
|
212
|
+
assert err.severity == pb.ErrorSeverity.ERROR
|
|
213
|
+
assert err.node == "store-tutorial"
|
|
214
|
+
assert err.sdk == "blok-python3"
|
|
215
|
+
assert err.runtime_kind == "runtime.python3"
|
|
216
|
+
assert err.message == "Postgres unreachable"
|
|
217
|
+
# `details_json` carries the original error payload for inspection.
|
|
218
|
+
details = json.loads(err.details_json)
|
|
219
|
+
assert details["message"] == "Postgres unreachable"
|
|
220
|
+
|
|
221
|
+
def test_vars_delta_serialized_when_present(self):
|
|
222
|
+
result = ExecutionResult.success_result({"ok": True})
|
|
223
|
+
result.with_vars({"cached": True})
|
|
224
|
+
proto = _encode_execute_response(
|
|
225
|
+
result,
|
|
226
|
+
node_name="x",
|
|
227
|
+
sdk_version="1.0.0",
|
|
228
|
+
)
|
|
229
|
+
assert json.loads(proto.vars_delta) == {"cached": True}
|
|
230
|
+
|
|
231
|
+
def test_vars_delta_empty_when_no_vars(self):
|
|
232
|
+
result = ExecutionResult.success_result({"ok": True})
|
|
233
|
+
proto = _encode_execute_response(
|
|
234
|
+
result,
|
|
235
|
+
node_name="x",
|
|
236
|
+
sdk_version="1.0.0",
|
|
237
|
+
)
|
|
238
|
+
assert proto.vars_delta == b""
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class TestInternalErrorToProto:
|
|
242
|
+
def test_string_error(self):
|
|
243
|
+
err = _internal_error_to_proto("plain string error", node_name="n", sdk_version="v")
|
|
244
|
+
assert err.message == "plain string error"
|
|
245
|
+
assert json.loads(err.details_json) == {"message": "plain string error"}
|
|
246
|
+
|
|
247
|
+
def test_none_error(self):
|
|
248
|
+
err = _internal_error_to_proto(None, node_name="n", sdk_version="v")
|
|
249
|
+
assert err.message == "node error"
|
|
250
|
+
assert err.details_json == b""
|
|
251
|
+
|
|
252
|
+
def test_dict_error_preserves_payload(self):
|
|
253
|
+
payload = {"message": "boom", "extra": {"sql": "08001"}}
|
|
254
|
+
err = _internal_error_to_proto(payload, node_name="n", sdk_version="v")
|
|
255
|
+
assert err.message == "boom"
|
|
256
|
+
assert json.loads(err.details_json) == payload
|
|
257
|
+
|
|
258
|
+
def test_unknown_type_falls_back_to_str(self):
|
|
259
|
+
err = _internal_error_to_proto(42, node_name="n", sdk_version="v")
|
|
260
|
+
assert err.message == "42"
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
"""End-to-end gRPC test for the Python SDK.
|
|
2
|
+
|
|
3
|
+
Spins up the ``BlokNodeRuntimeServicer`` on a random port, connects with a
|
|
4
|
+
grpc-python client, and exercises every RPC the v1 contract defines.
|
|
5
|
+
|
|
6
|
+
Mirrors ``sdks/rust/tests/grpc_integration.rs``.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import socket
|
|
12
|
+
from typing import Any, Dict
|
|
13
|
+
|
|
14
|
+
import grpc
|
|
15
|
+
import pytest
|
|
16
|
+
|
|
17
|
+
from blok.node.node_registry import NodeRegistry
|
|
18
|
+
from blok.runtime.v1 import runtime_pb2 as pb
|
|
19
|
+
from blok.runtime.v1 import runtime_pb2_grpc as pb_grpc
|
|
20
|
+
from blok.server.grpc_server import _encode_execute_response, _encode_json_bytes, serve_grpc
|
|
21
|
+
from blok.types.context import Context
|
|
22
|
+
from blok.types.execution_result import ExecutionMetrics, ExecutionResult
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _reserve_free_port() -> int:
|
|
26
|
+
"""Reserve an OS-chosen TCP port and immediately release it."""
|
|
27
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
|
28
|
+
sock.bind(("127.0.0.1", 0))
|
|
29
|
+
return sock.getsockname()[1]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class _EchoNode:
|
|
33
|
+
"""Minimal handler that echoes its config back as data."""
|
|
34
|
+
|
|
35
|
+
def execute(self, ctx: Context, config: Dict[str, Any]) -> Any:
|
|
36
|
+
return dict(config)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class _GreetNode:
|
|
40
|
+
"""Handler mirroring ``examples/hello_world_node.py`` for cross-runtime parity."""
|
|
41
|
+
|
|
42
|
+
def execute(self, ctx: Context, config: Dict[str, Any]) -> Any:
|
|
43
|
+
prefix = config.get("prefix", "Hello")
|
|
44
|
+
name = ctx.request.body_str("name") or "World"
|
|
45
|
+
ctx.set_var("greeting", f"{prefix}, {name}!")
|
|
46
|
+
return {
|
|
47
|
+
"message": f"{prefix}, {name}!",
|
|
48
|
+
"language": "python3",
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@pytest.fixture(scope="module")
|
|
53
|
+
def grpc_server_fixture():
|
|
54
|
+
"""Start a real gRPC server with two registered nodes; tear down after."""
|
|
55
|
+
port = _reserve_free_port()
|
|
56
|
+
registry = NodeRegistry(version="1.0.0-test")
|
|
57
|
+
registry.register("echo", _EchoNode())
|
|
58
|
+
registry.register("greet", _GreetNode())
|
|
59
|
+
|
|
60
|
+
server = serve_grpc(registry, port=port, host="127.0.0.1", sdk_version="1.0.0-test")
|
|
61
|
+
try:
|
|
62
|
+
yield port
|
|
63
|
+
finally:
|
|
64
|
+
server.stop(grace=1.0)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@pytest.fixture
|
|
68
|
+
def client(grpc_server_fixture):
|
|
69
|
+
"""Connect a NodeRuntimeStub to the server fixture."""
|
|
70
|
+
port = grpc_server_fixture
|
|
71
|
+
channel = grpc.insecure_channel(f"127.0.0.1:{port}")
|
|
72
|
+
yield pb_grpc.NodeRuntimeStub(channel)
|
|
73
|
+
channel.close()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _make_request(node_name: str, inputs: Dict[str, Any], body: Any = None) -> pb.ExecuteRequest:
|
|
77
|
+
return pb.ExecuteRequest(
|
|
78
|
+
node=pb.NodeRef(name=node_name, type="runtime.python3", version=""),
|
|
79
|
+
inputs=_encode_json_bytes(inputs),
|
|
80
|
+
step=pb.StepInfo(name=node_name, index=0, total=1, depth=0),
|
|
81
|
+
trigger=pb.TriggerInfo(
|
|
82
|
+
body=_encode_json_bytes(body) if body is not None else b"",
|
|
83
|
+
headers={"content-type": "application/json"} if body is not None else {},
|
|
84
|
+
params={},
|
|
85
|
+
query={},
|
|
86
|
+
cookies={},
|
|
87
|
+
method="POST",
|
|
88
|
+
url="/",
|
|
89
|
+
base_url="",
|
|
90
|
+
trigger_kind="http",
|
|
91
|
+
),
|
|
92
|
+
state=pb.RuntimeState(previous_output=b"", vars=b"", env={}),
|
|
93
|
+
workflow=pb.WorkflowInfo(
|
|
94
|
+
run_id="test-run",
|
|
95
|
+
name="test-wf",
|
|
96
|
+
path="/test",
|
|
97
|
+
version="1.0.0",
|
|
98
|
+
started_at=None,
|
|
99
|
+
),
|
|
100
|
+
options=pb.ExecuteOptions(deadline_ms=5000, stream_logs=False, capture_metrics=True, hints={}),
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# =============================================================================
|
|
105
|
+
# Tests
|
|
106
|
+
# =============================================================================
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_encode_response_keeps_content_type_out_of_data():
|
|
110
|
+
"""Regression — the `runtime.*` contentType leak (cross-runtime live test,
|
|
111
|
+
Finding #2). The node's return MUST be serialized as `data` verbatim, with
|
|
112
|
+
NO `contentType` key folded in; the content-type travels ONLY in the proto
|
|
113
|
+
`content_type` field (which the runner maps to the HTTP Content-Type header).
|
|
114
|
+
"""
|
|
115
|
+
node_return = {"message": "Hi, Ada!", "timestamp": "2026", "language": "python3"}
|
|
116
|
+
result = ExecutionResult.success_with_metrics(node_return, ExecutionMetrics(duration_ms=1.0))
|
|
117
|
+
|
|
118
|
+
resp = _encode_execute_response(result, node_name="hello-world", sdk_version="1.0.0")
|
|
119
|
+
|
|
120
|
+
# (a) data is the node's return verbatim — no contentType key.
|
|
121
|
+
decoded = json.loads(resp.data)
|
|
122
|
+
assert decoded == node_return
|
|
123
|
+
assert "contentType" not in decoded
|
|
124
|
+
# (b) content-type travels in the dedicated proto field.
|
|
125
|
+
assert resp.content_type == "application/json"
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def test_execute_returns_success_with_unwrapped_inputs(client):
|
|
129
|
+
"""Closes FIXES.md #3 at the wire layer for Python: inputs arrive UNWRAPPED."""
|
|
130
|
+
inputs = {"msg": "hello", "n": 42}
|
|
131
|
+
response = client.Execute(_make_request("echo", inputs))
|
|
132
|
+
|
|
133
|
+
assert response.success is True
|
|
134
|
+
assert response.error.code == "" # default empty proto value
|
|
135
|
+
assert json.loads(response.data) == inputs
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_execute_greet_node_uses_inputs_and_body(client):
|
|
139
|
+
"""Cross-runtime parity: same inputs/body produce the same shape Rust does."""
|
|
140
|
+
response = client.Execute(_make_request("greet", {"prefix": "Hi"}, {"name": "Blok"}))
|
|
141
|
+
|
|
142
|
+
assert response.success is True
|
|
143
|
+
data = json.loads(response.data)
|
|
144
|
+
assert data["message"] == "Hi, Blok!"
|
|
145
|
+
assert data["language"] == "python3"
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def test_execute_returns_structured_error_for_missing_node(client):
|
|
149
|
+
response = client.Execute(_make_request("does-not-exist", {}))
|
|
150
|
+
|
|
151
|
+
assert response.success is False
|
|
152
|
+
err = response.error
|
|
153
|
+
# Per master plan §17.7, the missing-node error path goes through
|
|
154
|
+
# BlokError.from_unknown which produces INTERNAL/UNCAUGHT_ERROR by
|
|
155
|
+
# default. The message still carries "not found" detail.
|
|
156
|
+
assert err.code == "UNCAUGHT_ERROR"
|
|
157
|
+
assert err.category == pb.ErrorCategory.INTERNAL
|
|
158
|
+
assert err.runtime_kind == "runtime.python3"
|
|
159
|
+
assert err.sdk == "blok-python3"
|
|
160
|
+
assert "not found" in err.message.lower()
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def test_health_reports_serving_with_registered_nodes(client):
|
|
164
|
+
response = client.Health(pb.HealthRequest(service="blok.runtime.v1.NodeRuntime"))
|
|
165
|
+
|
|
166
|
+
assert response.status == pb.HealthResponse.Status.SERVING
|
|
167
|
+
assert response.sdk_version == "1.0.0-test"
|
|
168
|
+
assert "echo" in response.registered_nodes
|
|
169
|
+
assert "greet" in response.registered_nodes
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def test_list_nodes_returns_registered_descriptors(client):
|
|
173
|
+
response = client.ListNodes(pb.ListNodesRequest())
|
|
174
|
+
|
|
175
|
+
assert response.sdk_name == "blok-python3"
|
|
176
|
+
assert response.sdk_version == "1.0.0-test"
|
|
177
|
+
assert response.proto_version == "1.0.0"
|
|
178
|
+
names = {n.name for n in response.nodes}
|
|
179
|
+
assert {"echo", "greet"}.issubset(names)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def test_execute_stream_emits_started_then_final(client):
|
|
183
|
+
events = list(client.ExecuteStream(_make_request("echo", {"shape": "round"})))
|
|
184
|
+
|
|
185
|
+
assert len(events) >= 2
|
|
186
|
+
assert events[0].WhichOneof("event") == "started"
|
|
187
|
+
assert events[-1].WhichOneof("event") == "final"
|
|
188
|
+
|
|
189
|
+
final = events[-1].final
|
|
190
|
+
assert final.success is True
|
|
191
|
+
assert json.loads(final.data) == {"shape": "round"}
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def test_execute_stream_streams_log_records_from_blok_node_logger(client):
|
|
195
|
+
"""A node that emits to ``blok.node`` logger should produce LogLine frames."""
|
|
196
|
+
import logging
|
|
197
|
+
|
|
198
|
+
class _LoggingNode:
|
|
199
|
+
def execute(self, ctx, config):
|
|
200
|
+
logging.getLogger("blok.node").info("hello from streaming")
|
|
201
|
+
logging.getLogger("blok.node").warning("almost done")
|
|
202
|
+
return {"ok": True}
|
|
203
|
+
|
|
204
|
+
# Register on the fly so we don't pollute the module-scoped fixture.
|
|
205
|
+
# The test client targets the same registry the fixture started; this
|
|
206
|
+
# registration mutates that shared registry.
|
|
207
|
+
from blok.runtime.v1 import runtime_pb2 as pb # noqa: F401 — already imported
|
|
208
|
+
# We can't reach the registry from `client` directly, so use a separate
|
|
209
|
+
# one-shot server for this test.
|
|
210
|
+
import socket as _socket
|
|
211
|
+
|
|
212
|
+
from blok.node.node_registry import NodeRegistry as _NR
|
|
213
|
+
from blok.server.grpc_server import serve_grpc as _serve
|
|
214
|
+
|
|
215
|
+
with _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM) as sock:
|
|
216
|
+
sock.bind(("127.0.0.1", 0))
|
|
217
|
+
port = sock.getsockname()[1]
|
|
218
|
+
|
|
219
|
+
reg = _NR(version="1.0.0-test")
|
|
220
|
+
reg.register("loggy", _LoggingNode())
|
|
221
|
+
srv = _serve(reg, port=port, host="127.0.0.1", sdk_version="1.0.0-test")
|
|
222
|
+
try:
|
|
223
|
+
ch = grpc.insecure_channel(f"127.0.0.1:{port}")
|
|
224
|
+
stub = pb_grpc.NodeRuntimeStub(ch)
|
|
225
|
+
events = list(stub.ExecuteStream(_make_request("loggy", {})))
|
|
226
|
+
ch.close()
|
|
227
|
+
finally:
|
|
228
|
+
srv.stop(grace=1.0)
|
|
229
|
+
|
|
230
|
+
types = [ev.WhichOneof("event") for ev in events]
|
|
231
|
+
assert types[0] == "started"
|
|
232
|
+
assert types[-1] == "final"
|
|
233
|
+
log_messages = [ev.log.message for ev in events if ev.WhichOneof("event") == "log"]
|
|
234
|
+
assert "hello from streaming" in log_messages
|
|
235
|
+
assert "almost done" in log_messages
|
|
236
|
+
log_levels = [ev.log.level for ev in events if ev.WhichOneof("event") == "log"]
|
|
237
|
+
assert "info" in log_levels
|
|
238
|
+
assert "warning" in log_levels
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def test_execute_stream_emits_partial_results_from_ctx_emit():
|
|
242
|
+
"""A node calling ``ctx.emit(...)`` produces ``PartialResult`` frames,
|
|
243
|
+
in order, before the terminal ``final`` frame — the live data channel
|
|
244
|
+
a ``streamTo: "sse"`` step forwards to the client."""
|
|
245
|
+
import socket as _socket
|
|
246
|
+
|
|
247
|
+
from blok.node.node_registry import NodeRegistry as _NR
|
|
248
|
+
from blok.server.grpc_server import serve_grpc as _serve
|
|
249
|
+
|
|
250
|
+
class _EmittingNode:
|
|
251
|
+
def execute(self, ctx, config):
|
|
252
|
+
ctx.emit({"event": "text", "data": {"delta": "Hel"}, "id": "1"})
|
|
253
|
+
ctx.emit({"event": "text", "data": {"delta": "lo"}, "id": "2"})
|
|
254
|
+
ctx.emit({"event": "source", "data": {"url": "https://example.com"}, "id": "3"})
|
|
255
|
+
return {"answer": "Hello", "sources": ["https://example.com"]}
|
|
256
|
+
|
|
257
|
+
with _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM) as sock:
|
|
258
|
+
sock.bind(("127.0.0.1", 0))
|
|
259
|
+
port = sock.getsockname()[1]
|
|
260
|
+
|
|
261
|
+
reg = _NR(version="1.0.0-test")
|
|
262
|
+
reg.register("emitter", _EmittingNode())
|
|
263
|
+
srv = _serve(reg, port=port, host="127.0.0.1", sdk_version="1.0.0-test")
|
|
264
|
+
try:
|
|
265
|
+
ch = grpc.insecure_channel(f"127.0.0.1:{port}")
|
|
266
|
+
stub = pb_grpc.NodeRuntimeStub(ch)
|
|
267
|
+
events = list(stub.ExecuteStream(_make_request("emitter", {})))
|
|
268
|
+
ch.close()
|
|
269
|
+
finally:
|
|
270
|
+
srv.stop(grace=1.0)
|
|
271
|
+
|
|
272
|
+
types = [ev.WhichOneof("event") for ev in events]
|
|
273
|
+
assert types[0] == "started"
|
|
274
|
+
assert types[-1] == "final"
|
|
275
|
+
|
|
276
|
+
partials = [json.loads(ev.partial.snapshot_json) for ev in events if ev.WhichOneof("event") == "partial"]
|
|
277
|
+
assert partials == [
|
|
278
|
+
{"event": "text", "data": {"delta": "Hel"}, "id": "1"},
|
|
279
|
+
{"event": "text", "data": {"delta": "lo"}, "id": "2"},
|
|
280
|
+
{"event": "source", "data": {"url": "https://example.com"}, "id": "3"},
|
|
281
|
+
]
|
|
282
|
+
|
|
283
|
+
# The terminal result is unaffected by the partials.
|
|
284
|
+
final = events[-1].final
|
|
285
|
+
assert final.success is True
|
|
286
|
+
assert json.loads(final.data) == {"answer": "Hello", "sources": ["https://example.com"]}
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def test_ctx_emit_is_a_noop_under_unary_execute(client):
|
|
290
|
+
"""``ctx.emit`` must be safe to call when there's no streaming sink — the
|
|
291
|
+
same handler runs under both ``Execute`` and ``ExecuteStream``."""
|
|
292
|
+
import socket as _socket
|
|
293
|
+
|
|
294
|
+
from blok.node.node_registry import NodeRegistry as _NR
|
|
295
|
+
from blok.server.grpc_server import serve_grpc as _serve
|
|
296
|
+
|
|
297
|
+
class _EmittingNode:
|
|
298
|
+
def execute(self, ctx, config):
|
|
299
|
+
ctx.emit({"event": "text", "data": "ignored under unary"})
|
|
300
|
+
return {"ok": True}
|
|
301
|
+
|
|
302
|
+
with _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM) as sock:
|
|
303
|
+
sock.bind(("127.0.0.1", 0))
|
|
304
|
+
port = sock.getsockname()[1]
|
|
305
|
+
|
|
306
|
+
reg = _NR(version="1.0.0-test")
|
|
307
|
+
reg.register("emitter", _EmittingNode())
|
|
308
|
+
srv = _serve(reg, port=port, host="127.0.0.1", sdk_version="1.0.0-test")
|
|
309
|
+
try:
|
|
310
|
+
ch = grpc.insecure_channel(f"127.0.0.1:{port}")
|
|
311
|
+
stub = pb_grpc.NodeRuntimeStub(ch)
|
|
312
|
+
resp = stub.Execute(_make_request("emitter", {}))
|
|
313
|
+
ch.close()
|
|
314
|
+
finally:
|
|
315
|
+
srv.stop(grace=1.0)
|
|
316
|
+
|
|
317
|
+
assert resp.success is True
|
|
318
|
+
assert json.loads(resp.data) == {"ok": True}
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def test_execute_stream_real_time_emits_log_before_final():
|
|
322
|
+
"""Logs emitted DURING a long-running handler arrive in the stream
|
|
323
|
+
before the final frame — proving the worker-thread + queue model
|
|
324
|
+
emits real-time, not just a buffered drain at the end (Phase 5
|
|
325
|
+
polish per master plan §17 follow-up).
|
|
326
|
+
"""
|
|
327
|
+
import logging
|
|
328
|
+
import socket as _socket
|
|
329
|
+
import time as _time
|
|
330
|
+
|
|
331
|
+
from blok.node.node_registry import NodeRegistry as _NR
|
|
332
|
+
from blok.runtime.v1 import runtime_pb2 as pb # noqa: F401
|
|
333
|
+
from blok.server.grpc_server import serve_grpc as _serve
|
|
334
|
+
|
|
335
|
+
log_emit_at: list[float] = []
|
|
336
|
+
log_arrival_at: list[float] = []
|
|
337
|
+
handler_done_at: list[float] = []
|
|
338
|
+
|
|
339
|
+
class _SlowLoggingNode:
|
|
340
|
+
def execute(self, ctx, config):
|
|
341
|
+
# Log first, sleep second. The real-time path must emit
|
|
342
|
+
# the log frame BEFORE the sleep finishes.
|
|
343
|
+
log_emit_at.append(_time.monotonic())
|
|
344
|
+
logging.getLogger("blok.node").info("emitted-before-sleep")
|
|
345
|
+
_time.sleep(0.5)
|
|
346
|
+
handler_done_at.append(_time.monotonic())
|
|
347
|
+
return {"ok": True}
|
|
348
|
+
|
|
349
|
+
with _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM) as sock:
|
|
350
|
+
sock.bind(("127.0.0.1", 0))
|
|
351
|
+
port = sock.getsockname()[1]
|
|
352
|
+
|
|
353
|
+
reg = _NR(version="1.0.0-test")
|
|
354
|
+
reg.register("slow-loggy", _SlowLoggingNode())
|
|
355
|
+
srv = _serve(reg, port=port, host="127.0.0.1", sdk_version="1.0.0-test")
|
|
356
|
+
try:
|
|
357
|
+
ch = grpc.insecure_channel(f"127.0.0.1:{port}")
|
|
358
|
+
stub = pb_grpc.NodeRuntimeStub(ch)
|
|
359
|
+
# Iterate manually so we can timestamp each event's arrival.
|
|
360
|
+
stream = stub.ExecuteStream(_make_request("slow-loggy", {}))
|
|
361
|
+
events = []
|
|
362
|
+
for ev in stream:
|
|
363
|
+
events.append(ev)
|
|
364
|
+
kind = ev.WhichOneof("event")
|
|
365
|
+
if kind == "log":
|
|
366
|
+
log_arrival_at.append(_time.monotonic())
|
|
367
|
+
ch.close()
|
|
368
|
+
finally:
|
|
369
|
+
srv.stop(grace=1.0)
|
|
370
|
+
|
|
371
|
+
types = [ev.WhichOneof("event") for ev in events]
|
|
372
|
+
assert types[0] == "started"
|
|
373
|
+
assert "log" in types
|
|
374
|
+
assert types[-1] == "final"
|
|
375
|
+
|
|
376
|
+
# The critical assertion: the log arrived BEFORE the handler
|
|
377
|
+
# finished. With the legacy buffered model the log_arrival_at
|
|
378
|
+
# entries would be later than handler_done_at[0] (drained after
|
|
379
|
+
# the handler returns); with the real-time model they must be
|
|
380
|
+
# earlier — within ~tens of milliseconds of the emit, well
|
|
381
|
+
# before the 500 ms sleep completes.
|
|
382
|
+
assert log_emit_at, "node never emitted"
|
|
383
|
+
assert log_arrival_at, "no log frame arrived in stream"
|
|
384
|
+
assert handler_done_at, "handler never returned"
|
|
385
|
+
arrival_lag = log_arrival_at[0] - log_emit_at[0]
|
|
386
|
+
handler_runtime = handler_done_at[0] - log_emit_at[0]
|
|
387
|
+
# Arrival should be much closer to emit than to handler completion.
|
|
388
|
+
# With the 50 ms poll tick the worst-case lag is ~50 ms; we allow
|
|
389
|
+
# 150 ms to absorb gRPC framing latency in CI.
|
|
390
|
+
assert arrival_lag < 0.15, (
|
|
391
|
+
f"log frame arrived {arrival_lag*1000:.1f}ms after emit (should be <150ms)"
|
|
392
|
+
)
|
|
393
|
+
# And it must arrive *before* the handler finishes — the whole
|
|
394
|
+
# point of real-time streaming.
|
|
395
|
+
assert log_arrival_at[0] < handler_done_at[0], (
|
|
396
|
+
f"log arrived after handler completed (lag {arrival_lag*1000:.1f}ms; "
|
|
397
|
+
f"handler ran {handler_runtime*1000:.1f}ms)"
|
|
398
|
+
)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Stage 1: Build
|
|
2
|
+
FROM ruby:3.2-alpine AS builder
|
|
3
|
+
|
|
4
|
+
RUN apk add --no-cache build-base
|
|
5
|
+
|
|
6
|
+
WORKDIR /app
|
|
7
|
+
|
|
8
|
+
COPY Gemfile blok.gemspec ./
|
|
9
|
+
COPY lib/blok/version.rb lib/blok/version.rb
|
|
10
|
+
|
|
11
|
+
RUN bundle install --without development test --jobs 4 --retry 3
|
|
12
|
+
|
|
13
|
+
COPY . .
|
|
14
|
+
|
|
15
|
+
# Stage 2: Production
|
|
16
|
+
FROM ruby:3.2-alpine
|
|
17
|
+
|
|
18
|
+
RUN apk add --no-cache libstdc++
|
|
19
|
+
|
|
20
|
+
WORKDIR /app
|
|
21
|
+
|
|
22
|
+
COPY --from=builder /usr/local/bundle /usr/local/bundle
|
|
23
|
+
COPY --from=builder /app /app
|
|
24
|
+
|
|
25
|
+
# HTTP port (informational /health) + gRPC port (the runner only speaks gRPC).
|
|
26
|
+
EXPOSE 8080 10006
|
|
27
|
+
|
|
28
|
+
ENV PORT=8080
|
|
29
|
+
ENV HOST=0.0.0.0
|
|
30
|
+
ENV GRPC_PORT=10006
|
|
31
|
+
ENV BLOK_TRANSPORT=grpc
|
|
32
|
+
ENV RACK_ENV=production
|
|
33
|
+
|
|
34
|
+
# bin/serve.rb honors BLOK_TRANSPORT and registers all 6 example nodes
|
|
35
|
+
# (typed-greet/chain-test included). `rackup config.ru` was HTTP-only and
|
|
36
|
+
# registered only 4 nodes — the runner reaches Ruby over gRPC.
|
|
37
|
+
CMD ["bundle", "exec", "ruby", "bin/serve.rb"]
|