blokctl 1.3.0 → 1.4.1

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.
Files changed (689) hide show
  1. package/dist/commands/create/project.js +15 -4
  2. package/dist/commands/create/utils/Examples.d.ts +1 -1
  3. package/dist/commands/create/utils/Examples.js +1 -1
  4. package/dist/commands/runtime/shared.js +4 -0
  5. package/dist/scaffold-repo/examples/ts-workflows/mcp-greeter.ts +59 -0
  6. package/dist/scaffold-repo/examples/ts-workflows/runtime-csharp-hello.ts +36 -0
  7. package/dist/scaffold-repo/examples/ts-workflows/runtime-go-hello.ts +36 -0
  8. package/dist/scaffold-repo/examples/ts-workflows/runtime-java-hello.ts +36 -0
  9. package/dist/scaffold-repo/examples/ts-workflows/runtime-php-hello.ts +36 -0
  10. package/dist/scaffold-repo/examples/ts-workflows/runtime-python3-hello.ts +36 -0
  11. package/dist/scaffold-repo/examples/ts-workflows/runtime-ruby-hello.ts +36 -0
  12. package/dist/scaffold-repo/examples/ts-workflows/runtime-rust-hello.ts +36 -0
  13. package/dist/scaffold-repo/infra/development/3055.dat +602 -0
  14. package/dist/scaffold-repo/infra/development/3057.dat +203 -0
  15. package/dist/scaffold-repo/infra/development/3059.dat +19 -0
  16. package/dist/scaffold-repo/infra/development/3061.dat +1003 -0
  17. package/dist/scaffold-repo/infra/development/3062.dat +5465 -0
  18. package/dist/scaffold-repo/infra/development/3063.dat +1003 -0
  19. package/dist/scaffold-repo/infra/development/3065.dat +606 -0
  20. package/dist/scaffold-repo/infra/development/3067.dat +603 -0
  21. package/dist/scaffold-repo/infra/development/3069.dat +112 -0
  22. package/dist/scaffold-repo/infra/development/3071.dat +4584 -0
  23. package/dist/scaffold-repo/infra/development/3073.dat +9 -0
  24. package/dist/scaffold-repo/infra/development/3075.dat +14599 -0
  25. package/dist/scaffold-repo/infra/development/3077.dat +16047 -0
  26. package/dist/scaffold-repo/infra/development/3079.dat +5 -0
  27. package/dist/scaffold-repo/infra/development/3081.dat +5 -0
  28. package/dist/scaffold-repo/infra/development/docker-compose.yml +106 -0
  29. package/dist/scaffold-repo/infra/development/schema.sql +1616 -0
  30. package/dist/scaffold-repo/infra/development/toc.dat +0 -0
  31. package/dist/scaffold-repo/infra/metrics/alertmanager.yml +43 -0
  32. package/dist/scaffold-repo/infra/metrics/alloy-config.alloy +75 -0
  33. package/dist/scaffold-repo/infra/metrics/dashboard.json +1152 -0
  34. package/dist/scaffold-repo/infra/metrics/dashboards/blok-overview.json +314 -0
  35. package/dist/scaffold-repo/infra/metrics/dashboards/blok-system.json +175 -0
  36. package/dist/scaffold-repo/infra/metrics/dashboards/blok-tracing.json +235 -0
  37. package/dist/scaffold-repo/infra/metrics/dashboards/blok-triggers.json +258 -0
  38. package/dist/scaffold-repo/infra/metrics/datasources.yml +43 -0
  39. package/dist/scaffold-repo/infra/metrics/default.yaml +8 -0
  40. package/dist/scaffold-repo/infra/metrics/docker-compose.yml +193 -0
  41. package/dist/scaffold-repo/infra/metrics/loki-config.yaml +50 -0
  42. package/dist/scaffold-repo/infra/metrics/nginx.conf +25 -0
  43. package/dist/scaffold-repo/infra/metrics/prometheus.yml +51 -0
  44. package/dist/scaffold-repo/infra/metrics/rules/blok-alerts.yml +114 -0
  45. package/dist/scaffold-repo/infra/metrics/telegraf.conf +41 -0
  46. package/dist/scaffold-repo/infra/metrics/tempo.yaml +81 -0
  47. package/dist/scaffold-repo/infra/milvus/docker-compose.yml +73 -0
  48. package/dist/scaffold-repo/sdk/javascript/README.md +151 -0
  49. package/dist/scaffold-repo/sdk/javascript/bootstrap.min.css +11660 -0
  50. package/dist/scaffold-repo/sdk/javascript/image-ai.html +316 -0
  51. package/dist/scaffold-repo/sdk/javascript/nanosdk.js +180 -0
  52. package/dist/scaffold-repo/sdk/javascript/nanosdk.min.js +100 -0
  53. package/dist/scaffold-repo/sdk/javascript/pdf.html +63 -0
  54. package/dist/scaffold-repo/sdk/javascript/test.html +68 -0
  55. package/dist/scaffold-repo/sdks/CLAUDE.md +67 -0
  56. package/dist/scaffold-repo/sdks/csharp/.dockerignore +7 -0
  57. package/dist/scaffold-repo/sdks/csharp/Blok.Core.sln +24 -0
  58. package/dist/scaffold-repo/sdks/csharp/Dockerfile +42 -0
  59. package/dist/scaffold-repo/sdks/csharp/README.md +138 -0
  60. package/dist/scaffold-repo/sdks/csharp/proto/blok/runtime/v1/runtime.proto +302 -0
  61. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Blok.Core.csproj +39 -0
  62. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Config/ServerConfig.cs +90 -0
  63. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/BlokError.cs +538 -0
  64. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/BlokErrorCategory.cs +112 -0
  65. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/BlokErrorSeverity.cs +40 -0
  66. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/BuildContextSnapshot.cs +168 -0
  67. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/ErrorCategory.cs +13 -0
  68. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/NodeException.cs +44 -0
  69. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Logging/LogEntry.cs +34 -0
  70. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Logging/LogLevel.cs +12 -0
  71. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Logging/Logger.cs +92 -0
  72. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Middleware/IMiddleware.cs +14 -0
  73. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Middleware/LoggingMiddleware.cs +46 -0
  74. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Middleware/MiddlewareChain.cs +35 -0
  75. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Middleware/RecoveryMiddleware.cs +63 -0
  76. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Node/INodeHandler.cs +17 -0
  77. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Node/NodeRegistry.cs +128 -0
  78. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Node/TypedNode.cs +140 -0
  79. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/ApiCallNode.cs +129 -0
  80. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/BlokErrorDemoNode.cs +125 -0
  81. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/ChainTestNode.cs +79 -0
  82. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/HelloWorldNode.cs +45 -0
  83. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/TransformDataNode.cs +119 -0
  84. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/TypedGreetNode.cs +23 -0
  85. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Program.cs +26 -0
  86. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Server/BlokNodeRuntimeService.cs +536 -0
  87. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Server/RuntimeServer.cs +183 -0
  88. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Testing/MockContextBuilder.cs +117 -0
  89. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Testing/TestNodeRunner.cs +50 -0
  90. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/Context.cs +56 -0
  91. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/ExecutionMetrics.cs +21 -0
  92. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/ExecutionRequest.cs +15 -0
  93. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/ExecutionResult.cs +104 -0
  94. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/HealthStatus.cs +18 -0
  95. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/NodeConfig.cs +59 -0
  96. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/Request.cs +57 -0
  97. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/Response.cs +24 -0
  98. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/UserNodeRegistry.cs +17 -0
  99. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Validation/SchemaValidator.cs +198 -0
  100. package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Blok.Core.Tests.csproj +25 -0
  101. package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Errors/BlokErrorTests.cs +458 -0
  102. package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Logging/LoggerTests.cs +129 -0
  103. package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Node/NodeRegistryTests.cs +145 -0
  104. package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Testing/MockContextTests.cs +153 -0
  105. package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/TypedNodeTests.cs +69 -0
  106. package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Types/ExecutionResultTests.cs +110 -0
  107. package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Validation/SchemaValidatorTests.cs +233 -0
  108. package/dist/scaffold-repo/sdks/go/Dockerfile +33 -0
  109. package/dist/scaffold-repo/sdks/go/README.md +255 -0
  110. package/dist/scaffold-repo/sdks/go/blok_error.go +803 -0
  111. package/dist/scaffold-repo/sdks/go/blok_error_test.go +433 -0
  112. package/dist/scaffold-repo/sdks/go/cmd/server/main.go +45 -0
  113. package/dist/scaffold-repo/sdks/go/cmd/server/register_user_nodes.go +12 -0
  114. package/dist/scaffold-repo/sdks/go/config.go +157 -0
  115. package/dist/scaffold-repo/sdks/go/config_test.go +129 -0
  116. package/dist/scaffold-repo/sdks/go/define_node.go +87 -0
  117. package/dist/scaffold-repo/sdks/go/define_node_test.go +75 -0
  118. package/dist/scaffold-repo/sdks/go/errors.go +104 -0
  119. package/dist/scaffold-repo/sdks/go/errors_test.go +95 -0
  120. package/dist/scaffold-repo/sdks/go/examples/nodes/apicall.go +117 -0
  121. package/dist/scaffold-repo/sdks/go/examples/nodes/blokerrordemo.go +80 -0
  122. package/dist/scaffold-repo/sdks/go/examples/nodes/chaintest.go +63 -0
  123. package/dist/scaffold-repo/sdks/go/examples/nodes/helloworld.go +41 -0
  124. package/dist/scaffold-repo/sdks/go/examples/nodes/transformdata.go +176 -0
  125. package/dist/scaffold-repo/sdks/go/examples/nodes/typedgreet.go +34 -0
  126. package/dist/scaffold-repo/sdks/go/genpb/blok/runtime/v1/runtime.pb.go +2070 -0
  127. package/dist/scaffold-repo/sdks/go/genpb/blok/runtime/v1/runtime_grpc.pb.go +273 -0
  128. package/dist/scaffold-repo/sdks/go/go.mod +25 -0
  129. package/dist/scaffold-repo/sdks/go/go.sum +66 -0
  130. package/dist/scaffold-repo/sdks/go/grpc_server.go +670 -0
  131. package/dist/scaffold-repo/sdks/go/grpc_server_test.go +474 -0
  132. package/dist/scaffold-repo/sdks/go/logging.go +144 -0
  133. package/dist/scaffold-repo/sdks/go/logging_test.go +139 -0
  134. package/dist/scaffold-repo/sdks/go/middleware.go +152 -0
  135. package/dist/scaffold-repo/sdks/go/middleware_test.go +222 -0
  136. package/dist/scaffold-repo/sdks/go/node.go +50 -0
  137. package/dist/scaffold-repo/sdks/go/proto/blok/runtime/v1/runtime.proto +302 -0
  138. package/dist/scaffold-repo/sdks/go/registry.go +156 -0
  139. package/dist/scaffold-repo/sdks/go/registry_test.go +195 -0
  140. package/dist/scaffold-repo/sdks/go/server.go +207 -0
  141. package/dist/scaffold-repo/sdks/go/server_test.go +186 -0
  142. package/dist/scaffold-repo/sdks/go/shutdown.go +32 -0
  143. package/dist/scaffold-repo/sdks/go/testutil.go +169 -0
  144. package/dist/scaffold-repo/sdks/go/testutil_test.go +124 -0
  145. package/dist/scaffold-repo/sdks/go/types.go +295 -0
  146. package/dist/scaffold-repo/sdks/go/types_test.go +251 -0
  147. package/dist/scaffold-repo/sdks/go/validation.go +210 -0
  148. package/dist/scaffold-repo/sdks/go/validation_test.go +262 -0
  149. package/dist/scaffold-repo/sdks/go/worker.go +577 -0
  150. package/dist/scaffold-repo/sdks/java/Dockerfile +33 -0
  151. package/dist/scaffold-repo/sdks/java/README.md +221 -0
  152. package/dist/scaffold-repo/sdks/java/pom.xml +163 -0
  153. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/Main.java +90 -0
  154. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/UserNodeRegistry.java +19 -0
  155. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/config/ServerConfig.java +244 -0
  156. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/BlokError.java +576 -0
  157. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/BlokErrorCategory.java +68 -0
  158. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/BlokErrorSeverity.java +31 -0
  159. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/BuildContextSnapshot.java +132 -0
  160. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/ErrorCategory.java +22 -0
  161. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/NodeException.java +176 -0
  162. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/logging/LogEntry.java +78 -0
  163. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/logging/LogLevel.java +48 -0
  164. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/logging/Logger.java +160 -0
  165. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/middleware/LoggingMiddleware.java +65 -0
  166. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/middleware/Middleware.java +29 -0
  167. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/middleware/MiddlewareChain.java +59 -0
  168. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/middleware/RecoveryMiddleware.java +53 -0
  169. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/node/NodeHandler.java +40 -0
  170. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/node/NodeReflector.java +18 -0
  171. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/node/NodeRegistry.java +205 -0
  172. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/node/TypedNode.java +143 -0
  173. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/ApiCallNode.java +145 -0
  174. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/BlokErrorDemoNode.java +109 -0
  175. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/ChainTestNode.java +65 -0
  176. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/HelloWorldNode.java +62 -0
  177. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/TransformDataNode.java +121 -0
  178. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/TypedGreetNode.java +41 -0
  179. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/server/BlokGrpcServer.java +103 -0
  180. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/server/BlokNodeRuntimeService.java +501 -0
  181. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/server/RuntimeServer.java +176 -0
  182. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/testing/MockContext.java +120 -0
  183. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/testing/TestRunner.java +59 -0
  184. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/Context.java +167 -0
  185. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/ExecutionMetrics.java +80 -0
  186. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/ExecutionRequest.java +61 -0
  187. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/ExecutionResult.java +188 -0
  188. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/HealthStatus.java +77 -0
  189. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/NodeConfig.java +139 -0
  190. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/Request.java +154 -0
  191. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/Response.java +77 -0
  192. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/validation/SchemaValidator.java +178 -0
  193. package/dist/scaffold-repo/sdks/java/src/main/proto/blok/runtime/v1/runtime.proto +302 -0
  194. package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/errors/BlokErrorTest.java +416 -0
  195. package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/logging/LoggerTest.java +176 -0
  196. package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/node/NodeRegistryTest.java +227 -0
  197. package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/node/TypedNodeTest.java +76 -0
  198. package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/server/RuntimeServerTest.java +197 -0
  199. package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/types/ExecutionResultTest.java +194 -0
  200. package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/validation/SchemaValidatorTest.java +246 -0
  201. package/dist/scaffold-repo/sdks/php/.rr.yaml +29 -0
  202. package/dist/scaffold-repo/sdks/php/Dockerfile +61 -0
  203. package/dist/scaffold-repo/sdks/php/README.md +387 -0
  204. package/dist/scaffold-repo/sdks/php/bin/serve.php +95 -0
  205. package/dist/scaffold-repo/sdks/php/composer.json +41 -0
  206. package/dist/scaffold-repo/sdks/php/examples/ApiCallNode.php +103 -0
  207. package/dist/scaffold-repo/sdks/php/examples/BlokErrorDemoNode.php +90 -0
  208. package/dist/scaffold-repo/sdks/php/examples/ChainTestNode.php +56 -0
  209. package/dist/scaffold-repo/sdks/php/examples/HelloWorldNode.php +39 -0
  210. package/dist/scaffold-repo/sdks/php/examples/TransformDataNode.php +94 -0
  211. package/dist/scaffold-repo/sdks/php/examples/TypedGreetNode.php +57 -0
  212. package/dist/scaffold-repo/sdks/php/phpunit.xml +23 -0
  213. package/dist/scaffold-repo/sdks/php/proto/blok/runtime/v1/runtime.proto +302 -0
  214. package/dist/scaffold-repo/sdks/php/src/Config/ServerConfig.php +83 -0
  215. package/dist/scaffold-repo/sdks/php/src/Errors/BlokError.php +467 -0
  216. package/dist/scaffold-repo/sdks/php/src/Errors/BlokErrorBuilder.php +121 -0
  217. package/dist/scaffold-repo/sdks/php/src/Errors/BlokErrorCategory.php +83 -0
  218. package/dist/scaffold-repo/sdks/php/src/Errors/BlokErrorSeverity.php +30 -0
  219. package/dist/scaffold-repo/sdks/php/src/Errors/BuildContextSnapshot.php +141 -0
  220. package/dist/scaffold-repo/sdks/php/src/Errors/ErrorCategory.php +17 -0
  221. package/dist/scaffold-repo/sdks/php/src/Errors/NodeException.php +107 -0
  222. package/dist/scaffold-repo/sdks/php/src/Errors/Origin.php +35 -0
  223. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ErrorCategory.php +118 -0
  224. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ErrorSeverity.php +72 -0
  225. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ExecuteEvent.php +181 -0
  226. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ExecuteOptions.php +159 -0
  227. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ExecuteRequest.php +328 -0
  228. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ExecuteResponse.php +288 -0
  229. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/HealthRequest.php +59 -0
  230. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/HealthResponse/Status.php +54 -0
  231. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/HealthResponse.php +113 -0
  232. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ListNodesRequest.php +32 -0
  233. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ListNodesResponse.php +154 -0
  234. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/LogLine.php +156 -0
  235. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/Metrics.php +165 -0
  236. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeDescriptor.php +174 -0
  237. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeError.php +627 -0
  238. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeRef.php +134 -0
  239. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeRuntimeClient.php +101 -0
  240. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeStarted.php +68 -0
  241. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/PartialResult.php +59 -0
  242. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/Progress.php +85 -0
  243. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/RuntimeState.php +142 -0
  244. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/StepInfo.php +168 -0
  245. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/TriggerInfo.php +289 -0
  246. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/WorkflowInfo.php +176 -0
  247. package/dist/scaffold-repo/sdks/php/src/Genpb/GPBMetadata/Blok/Runtime/V1/Runtime.php +26 -0
  248. package/dist/scaffold-repo/sdks/php/src/Logging/LogEntry.php +47 -0
  249. package/dist/scaffold-repo/sdks/php/src/Logging/LogLevel.php +50 -0
  250. package/dist/scaffold-repo/sdks/php/src/Logging/Logger.php +133 -0
  251. package/dist/scaffold-repo/sdks/php/src/Node/NodeHandler.php +35 -0
  252. package/dist/scaffold-repo/sdks/php/src/Node/NodeReflector.php +21 -0
  253. package/dist/scaffold-repo/sdks/php/src/Node/NodeRegistry.php +172 -0
  254. package/dist/scaffold-repo/sdks/php/src/Node/TypedNode.php +159 -0
  255. package/dist/scaffold-repo/sdks/php/src/Server/BlokNodeRuntimeService.php +504 -0
  256. package/dist/scaffold-repo/sdks/php/src/Server/DecodeException.php +13 -0
  257. package/dist/scaffold-repo/sdks/php/src/Server/Middleware.php +18 -0
  258. package/dist/scaffold-repo/sdks/php/src/Server/MiddlewarePipeline.php +33 -0
  259. package/dist/scaffold-repo/sdks/php/src/Server/NodeRuntimeInterface.php +40 -0
  260. package/dist/scaffold-repo/sdks/php/src/Server/Server.php +157 -0
  261. package/dist/scaffold-repo/sdks/php/src/Testing/MockContext.php +161 -0
  262. package/dist/scaffold-repo/sdks/php/src/Testing/TestRunner.php +78 -0
  263. package/dist/scaffold-repo/sdks/php/src/Types/Context.php +80 -0
  264. package/dist/scaffold-repo/sdks/php/src/Types/ExecutionMetrics.php +48 -0
  265. package/dist/scaffold-repo/sdks/php/src/Types/ExecutionRequest.php +38 -0
  266. package/dist/scaffold-repo/sdks/php/src/Types/ExecutionResult.php +143 -0
  267. package/dist/scaffold-repo/sdks/php/src/Types/HealthStatus.php +42 -0
  268. package/dist/scaffold-repo/sdks/php/src/Types/NodeConfig.php +72 -0
  269. package/dist/scaffold-repo/sdks/php/src/Types/Request.php +82 -0
  270. package/dist/scaffold-repo/sdks/php/src/Types/Response.php +44 -0
  271. package/dist/scaffold-repo/sdks/php/src/Validation/SchemaValidator.php +197 -0
  272. package/dist/scaffold-repo/sdks/php/tests/Errors/BlokErrorTest.php +402 -0
  273. package/dist/scaffold-repo/sdks/php/tests/Logging/LoggerTest.php +165 -0
  274. package/dist/scaffold-repo/sdks/php/tests/Node/NodeRegistryTest.php +139 -0
  275. package/dist/scaffold-repo/sdks/php/tests/Node/TypedNodeTest.php +84 -0
  276. package/dist/scaffold-repo/sdks/php/tests/Server/BlokNodeRuntimeServiceTest.php +288 -0
  277. package/dist/scaffold-repo/sdks/php/tests/Testing/MockContextTest.php +184 -0
  278. package/dist/scaffold-repo/sdks/php/tests/Types/ExecutionResultTest.php +136 -0
  279. package/dist/scaffold-repo/sdks/php/tests/Validation/SchemaValidatorTest.php +191 -0
  280. package/dist/scaffold-repo/sdks/python3/Dockerfile +62 -0
  281. package/dist/scaffold-repo/sdks/python3/bin/serve.py +174 -0
  282. package/dist/scaffold-repo/sdks/python3/bin/worker.py +60 -0
  283. package/dist/scaffold-repo/sdks/python3/blok/__init__.py +61 -0
  284. package/dist/scaffold-repo/sdks/python3/blok/config/__init__.py +3 -0
  285. package/dist/scaffold-repo/sdks/python3/blok/config/server_config.py +116 -0
  286. package/dist/scaffold-repo/sdks/python3/blok/errors/__init__.py +50 -0
  287. package/dist/scaffold-repo/sdks/python3/blok/errors/blok_error.py +555 -0
  288. package/dist/scaffold-repo/sdks/python3/blok/errors/node_error.py +64 -0
  289. package/dist/scaffold-repo/sdks/python3/blok/logging/__init__.py +3 -0
  290. package/dist/scaffold-repo/sdks/python3/blok/logging/logger.py +82 -0
  291. package/dist/scaffold-repo/sdks/python3/blok/middleware/__init__.py +4 -0
  292. package/dist/scaffold-repo/sdks/python3/blok/middleware/logging_middleware.py +35 -0
  293. package/dist/scaffold-repo/sdks/python3/blok/middleware/recovery_middleware.py +36 -0
  294. package/dist/scaffold-repo/sdks/python3/blok/node/__init__.py +4 -0
  295. package/dist/scaffold-repo/sdks/python3/blok/node/define_node.py +239 -0
  296. package/dist/scaffold-repo/sdks/python3/blok/node/node_handler.py +35 -0
  297. package/dist/scaffold-repo/sdks/python3/blok/node/node_registry.py +136 -0
  298. package/dist/scaffold-repo/sdks/python3/blok/runtime/__init__.py +0 -0
  299. package/dist/scaffold-repo/sdks/python3/blok/runtime/v1/__init__.py +0 -0
  300. package/dist/scaffold-repo/sdks/python3/blok/runtime/v1/runtime_pb2.py +112 -0
  301. package/dist/scaffold-repo/sdks/python3/blok/runtime/v1/runtime_pb2_grpc.py +259 -0
  302. package/dist/scaffold-repo/sdks/python3/blok/server/__init__.py +3 -0
  303. package/dist/scaffold-repo/sdks/python3/blok/server/grpc_server.py +757 -0
  304. package/dist/scaffold-repo/sdks/python3/blok/server/runtime_server.py +165 -0
  305. package/dist/scaffold-repo/sdks/python3/blok/types/__init__.py +13 -0
  306. package/dist/scaffold-repo/sdks/python3/blok/types/context.py +162 -0
  307. package/dist/scaffold-repo/sdks/python3/blok/types/execution_request.py +74 -0
  308. package/dist/scaffold-repo/sdks/python3/blok/types/execution_result.py +103 -0
  309. package/dist/scaffold-repo/sdks/python3/blok/worker/__init__.py +10 -0
  310. package/dist/scaffold-repo/sdks/python3/blok/worker/job_message.py +34 -0
  311. package/dist/scaffold-repo/sdks/python3/blok/worker/worker.py +451 -0
  312. package/dist/scaffold-repo/sdks/python3/blok/worker/worker_config.py +129 -0
  313. package/dist/scaffold-repo/sdks/python3/examples/__init__.py +32 -0
  314. package/dist/scaffold-repo/sdks/python3/examples/api_call_node.py +85 -0
  315. package/dist/scaffold-repo/sdks/python3/examples/blok_error_demo_node.py +79 -0
  316. package/dist/scaffold-repo/sdks/python3/examples/chain_test_node.py +51 -0
  317. package/dist/scaffold-repo/sdks/python3/examples/hello_world_node.py +44 -0
  318. package/dist/scaffold-repo/sdks/python3/examples/transform_data_node.py +71 -0
  319. package/dist/scaffold-repo/sdks/python3/examples/typed_greet_node.py +25 -0
  320. package/dist/scaffold-repo/sdks/python3/proto/blok/runtime/v1/runtime.proto +302 -0
  321. package/dist/scaffold-repo/sdks/python3/pyproject.toml +47 -0
  322. package/dist/scaffold-repo/sdks/python3/requirements.txt +17 -0
  323. package/dist/scaffold-repo/sdks/python3/tests/__init__.py +0 -0
  324. package/dist/scaffold-repo/sdks/python3/tests/test_blok_error.py +341 -0
  325. package/dist/scaffold-repo/sdks/python3/tests/test_define_node.py +135 -0
  326. package/dist/scaffold-repo/sdks/python3/tests/test_discovery.py +99 -0
  327. package/dist/scaffold-repo/sdks/python3/tests/test_grpc_codec.py +260 -0
  328. package/dist/scaffold-repo/sdks/python3/tests/test_grpc_server.py +398 -0
  329. package/dist/scaffold-repo/sdks/ruby/Dockerfile +37 -0
  330. package/dist/scaffold-repo/sdks/ruby/Gemfile +5 -0
  331. package/dist/scaffold-repo/sdks/ruby/README.md +210 -0
  332. package/dist/scaffold-repo/sdks/ruby/Rakefile +11 -0
  333. package/dist/scaffold-repo/sdks/ruby/bin/serve.rb +105 -0
  334. package/dist/scaffold-repo/sdks/ruby/blok.gemspec +43 -0
  335. package/dist/scaffold-repo/sdks/ruby/config.ru +15 -0
  336. package/dist/scaffold-repo/sdks/ruby/examples/api_call_node.rb +99 -0
  337. package/dist/scaffold-repo/sdks/ruby/examples/blok_error_demo_node.rb +79 -0
  338. package/dist/scaffold-repo/sdks/ruby/examples/chain_test_node.rb +51 -0
  339. package/dist/scaffold-repo/sdks/ruby/examples/hello_world_node.rb +40 -0
  340. package/dist/scaffold-repo/sdks/ruby/examples/transform_data_node.rb +82 -0
  341. package/dist/scaffold-repo/sdks/ruby/examples/typed_greet_node.rb +25 -0
  342. package/dist/scaffold-repo/sdks/ruby/lib/blok/config/server_config.rb +76 -0
  343. package/dist/scaffold-repo/sdks/ruby/lib/blok/errors/blok_error.rb +476 -0
  344. package/dist/scaffold-repo/sdks/ruby/lib/blok/errors/build_context_snapshot.rb +99 -0
  345. package/dist/scaffold-repo/sdks/ruby/lib/blok/errors/error_category.rb +16 -0
  346. package/dist/scaffold-repo/sdks/ruby/lib/blok/errors/node_error.rb +84 -0
  347. package/dist/scaffold-repo/sdks/ruby/lib/blok/logging/log_entry.rb +46 -0
  348. package/dist/scaffold-repo/sdks/ruby/lib/blok/logging/log_level.rb +49 -0
  349. package/dist/scaffold-repo/sdks/ruby/lib/blok/logging/logger.rb +71 -0
  350. package/dist/scaffold-repo/sdks/ruby/lib/blok/middleware/logging_middleware.rb +45 -0
  351. package/dist/scaffold-repo/sdks/ruby/lib/blok/middleware/middleware.rb +36 -0
  352. package/dist/scaffold-repo/sdks/ruby/lib/blok/middleware/recovery_middleware.rb +31 -0
  353. package/dist/scaffold-repo/sdks/ruby/lib/blok/node/discovery.rb +59 -0
  354. package/dist/scaffold-repo/sdks/ruby/lib/blok/node/node_handler.rb +43 -0
  355. package/dist/scaffold-repo/sdks/ruby/lib/blok/node/node_registry.rb +107 -0
  356. package/dist/scaffold-repo/sdks/ruby/lib/blok/node/typed_node.rb +180 -0
  357. package/dist/scaffold-repo/sdks/ruby/lib/blok/runtime/v1/runtime_pb.rb +43 -0
  358. package/dist/scaffold-repo/sdks/ruby/lib/blok/runtime/v1/runtime_services_pb.rb +55 -0
  359. package/dist/scaffold-repo/sdks/ruby/lib/blok/server/grpc_server.rb +435 -0
  360. package/dist/scaffold-repo/sdks/ruby/lib/blok/server/runtime_app.rb +86 -0
  361. package/dist/scaffold-repo/sdks/ruby/lib/blok/testing/mock_context.rb +109 -0
  362. package/dist/scaffold-repo/sdks/ruby/lib/blok/testing/test_runner.rb +40 -0
  363. package/dist/scaffold-repo/sdks/ruby/lib/blok/types/context.rb +82 -0
  364. package/dist/scaffold-repo/sdks/ruby/lib/blok/types/execution_metrics.rb +43 -0
  365. package/dist/scaffold-repo/sdks/ruby/lib/blok/types/execution_request.rb +39 -0
  366. package/dist/scaffold-repo/sdks/ruby/lib/blok/types/execution_result.rb +117 -0
  367. package/dist/scaffold-repo/sdks/ruby/lib/blok/types/health_status.rb +42 -0
  368. package/dist/scaffold-repo/sdks/ruby/lib/blok/types/node_config.rb +73 -0
  369. package/dist/scaffold-repo/sdks/ruby/lib/blok/types/request.rb +71 -0
  370. package/dist/scaffold-repo/sdks/ruby/lib/blok/types/response.rb +46 -0
  371. package/dist/scaffold-repo/sdks/ruby/lib/blok/validation/schema_validator.rb +142 -0
  372. package/dist/scaffold-repo/sdks/ruby/lib/blok/version.rb +5 -0
  373. package/dist/scaffold-repo/sdks/ruby/lib/blok.rb +53 -0
  374. package/dist/scaffold-repo/sdks/ruby/proto/blok/runtime/v1/runtime.proto +302 -0
  375. package/dist/scaffold-repo/sdks/ruby/test/errors/blok_error_test.rb +339 -0
  376. package/dist/scaffold-repo/sdks/ruby/test/logging/logger_test.rb +155 -0
  377. package/dist/scaffold-repo/sdks/ruby/test/node/node_registry_test.rb +132 -0
  378. package/dist/scaffold-repo/sdks/ruby/test/node/typed_node_test.rb +67 -0
  379. package/dist/scaffold-repo/sdks/ruby/test/test_helper.rb +6 -0
  380. package/dist/scaffold-repo/sdks/ruby/test/testing/mock_context_test.rb +150 -0
  381. package/dist/scaffold-repo/sdks/ruby/test/types/execution_result_test.rb +129 -0
  382. package/dist/scaffold-repo/sdks/ruby/test/validation/schema_validator_test.rb +270 -0
  383. package/dist/scaffold-repo/sdks/rust/Cargo.lock +3044 -0
  384. package/dist/scaffold-repo/sdks/rust/Cargo.toml +82 -0
  385. package/dist/scaffold-repo/sdks/rust/Dockerfile +40 -0
  386. package/dist/scaffold-repo/sdks/rust/README.md +73 -0
  387. package/dist/scaffold-repo/sdks/rust/build.rs +32 -0
  388. package/dist/scaffold-repo/sdks/rust/proto/blok/runtime/v1/runtime.proto +302 -0
  389. package/dist/scaffold-repo/sdks/rust/src/blok_error.rs +1168 -0
  390. package/dist/scaffold-repo/sdks/rust/src/config.rs +158 -0
  391. package/dist/scaffold-repo/sdks/rust/src/errors.rs +142 -0
  392. package/dist/scaffold-repo/sdks/rust/src/grpc_server.rs +635 -0
  393. package/dist/scaffold-repo/sdks/rust/src/lib.rs +65 -0
  394. package/dist/scaffold-repo/sdks/rust/src/logging.rs +195 -0
  395. package/dist/scaffold-repo/sdks/rust/src/main.rs +79 -0
  396. package/dist/scaffold-repo/sdks/rust/src/middleware.rs +181 -0
  397. package/dist/scaffold-repo/sdks/rust/src/node.rs +172 -0
  398. package/dist/scaffold-repo/sdks/rust/src/nodes/api_call.rs +93 -0
  399. package/dist/scaffold-repo/sdks/rust/src/nodes/blok_error_demo.rs +151 -0
  400. package/dist/scaffold-repo/sdks/rust/src/nodes/chain_test.rs +57 -0
  401. package/dist/scaffold-repo/sdks/rust/src/nodes/hello_world.rs +83 -0
  402. package/dist/scaffold-repo/sdks/rust/src/nodes/mod.rs +18 -0
  403. package/dist/scaffold-repo/sdks/rust/src/nodes/transform_data.rs +142 -0
  404. package/dist/scaffold-repo/sdks/rust/src/nodes/typed_greet.rs +56 -0
  405. package/dist/scaffold-repo/sdks/rust/src/registry.rs +204 -0
  406. package/dist/scaffold-repo/sdks/rust/src/server.rs +63 -0
  407. package/dist/scaffold-repo/sdks/rust/src/testing.rs +175 -0
  408. package/dist/scaffold-repo/sdks/rust/src/types.rs +338 -0
  409. package/dist/scaffold-repo/sdks/rust/src/user_nodes/mod.rs +10 -0
  410. package/dist/scaffold-repo/sdks/rust/src/validation.rs +232 -0
  411. package/dist/scaffold-repo/sdks/rust/src/worker.rs +509 -0
  412. package/dist/scaffold-repo/sdks/rust/tests/grpc_integration.rs +306 -0
  413. package/dist/scaffold-repo/sdks/rust/tests/typed_node.rs +104 -0
  414. package/dist/scaffold-repo/triggers/cron/CHANGELOG.md +22 -0
  415. package/dist/scaffold-repo/triggers/cron/package.json +36 -0
  416. package/dist/scaffold-repo/triggers/cron/src/CronTrigger.ts +552 -0
  417. package/dist/scaffold-repo/triggers/cron/src/index.ts +77 -0
  418. package/dist/scaffold-repo/triggers/cron/tsconfig.json +32 -0
  419. package/dist/scaffold-repo/triggers/grpc/.env.example +8 -0
  420. package/dist/scaffold-repo/triggers/grpc/CHANGELOG.md +143 -0
  421. package/dist/scaffold-repo/triggers/grpc/README.md +25 -0
  422. package/dist/scaffold-repo/triggers/grpc/buf.gen.yaml +11 -0
  423. package/dist/scaffold-repo/triggers/grpc/buf.yaml +9 -0
  424. package/dist/scaffold-repo/triggers/grpc/localhost+2-key.pem +28 -0
  425. package/dist/scaffold-repo/triggers/grpc/localhost+2.pem +27 -0
  426. package/dist/scaffold-repo/triggers/grpc/package.json +61 -0
  427. package/dist/scaffold-repo/triggers/grpc/proto/workflow.proto +33 -0
  428. package/dist/scaffold-repo/triggers/grpc/src/GRpcTrigger.ts +297 -0
  429. package/dist/scaffold-repo/triggers/grpc/src/GrpcClient.ts +87 -0
  430. package/dist/scaffold-repo/triggers/grpc/src/GrpcServer.ts +68 -0
  431. package/dist/scaffold-repo/triggers/grpc/src/MessageDecode.ts +142 -0
  432. package/dist/scaffold-repo/triggers/grpc/src/NanoSDK.ts +146 -0
  433. package/dist/scaffold-repo/triggers/grpc/src/Nodes.ts +10 -0
  434. package/dist/scaffold-repo/triggers/grpc/src/Workflows.ts +5 -0
  435. package/dist/scaffold-repo/triggers/grpc/src/gen/workflow_pb.ts +142 -0
  436. package/dist/scaffold-repo/triggers/grpc/src/index.ts +22 -0
  437. package/dist/scaffold-repo/triggers/grpc/src/server.ts +8 -0
  438. package/dist/scaffold-repo/triggers/grpc/src/types/Message.ts +0 -0
  439. package/dist/scaffold-repo/triggers/grpc/src/types/RuntimeWorkflow.ts +7 -0
  440. package/dist/scaffold-repo/triggers/grpc/src/types/Workflows.ts +7 -0
  441. package/dist/scaffold-repo/triggers/grpc/tsconfig.json +34 -0
  442. package/dist/scaffold-repo/triggers/grpc/vitest.config.ts +29 -0
  443. package/dist/scaffold-repo/triggers/grpc/workflows/countries.json +27 -0
  444. package/dist/scaffold-repo/triggers/http/.blok/trace.db +0 -0
  445. package/dist/scaffold-repo/triggers/http/.blok/trace.db-shm +0 -0
  446. package/dist/scaffold-repo/triggers/http/.blok/trace.db-wal +0 -0
  447. package/dist/scaffold-repo/triggers/http/.dockerignore +23 -0
  448. package/dist/scaffold-repo/triggers/http/.env.example +8 -0
  449. package/dist/scaffold-repo/triggers/http/CHANGELOG.md +326 -0
  450. package/dist/scaffold-repo/triggers/http/Dockerfile +49 -0
  451. package/dist/scaffold-repo/triggers/http/Dockerfile.dev +34 -0
  452. package/dist/scaffold-repo/triggers/http/infra/docker-compose.yml +38 -0
  453. package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Authentication.md +74 -0
  454. package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Building.md +52 -0
  455. package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Create_Node.md +123 -0
  456. package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Create_Workflow.md +177 -0
  457. package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Deployment.md +69 -0
  458. package/dist/scaffold-repo/triggers/http/notes/Core_Concepts/Context.md +156 -0
  459. package/dist/scaffold-repo/triggers/http/notes/examples.md +104 -0
  460. package/dist/scaffold-repo/triggers/http/notes/index.md +51 -0
  461. package/dist/scaffold-repo/triggers/http/package.json +62 -0
  462. package/dist/scaffold-repo/triggers/http/public/favicon.ico +0 -0
  463. package/dist/scaffold-repo/triggers/http/public/metric/index.html +2101 -0
  464. package/dist/scaffold-repo/triggers/http/request.http +7 -0
  465. package/dist/scaffold-repo/triggers/http/src/AppRoutes.ts +64 -0
  466. package/dist/scaffold-repo/triggers/http/src/Nodes.ts +38 -0
  467. package/dist/scaffold-repo/triggers/http/src/Workflows.ts +18 -0
  468. package/dist/scaffold-repo/triggers/http/src/index.ts +86 -0
  469. package/dist/scaffold-repo/triggers/http/src/nodes/chain-init/index.ts +48 -0
  470. package/dist/scaffold-repo/triggers/http/src/nodes/chain-verify/index.ts +123 -0
  471. package/dist/scaffold-repo/triggers/http/src/nodes/eval/index.ts +69 -0
  472. package/dist/scaffold-repo/triggers/http/src/nodes/examples/README.md +14 -0
  473. package/dist/scaffold-repo/triggers/http/src/nodes/examples/chat-ui/index.html +228 -0
  474. package/dist/scaffold-repo/triggers/http/src/nodes/examples/chat-ui/index.ts +65 -0
  475. package/dist/scaffold-repo/triggers/http/src/nodes/examples/index.ts +14 -0
  476. package/dist/scaffold-repo/triggers/http/src/nodes/runtime-bridge/index.ts +84 -0
  477. package/dist/scaffold-repo/triggers/http/src/runner/HonoTraceRouterAdapter.ts +199 -0
  478. package/dist/scaffold-repo/triggers/http/src/runner/HttpTrigger.ts +2039 -0
  479. package/dist/scaffold-repo/triggers/http/src/runner/MessageDecode.ts +57 -0
  480. package/dist/scaffold-repo/triggers/http/src/runner/Util.ts +52 -0
  481. package/dist/scaffold-repo/triggers/http/src/runner/WorkflowRouter.ts +411 -0
  482. package/dist/scaffold-repo/triggers/http/src/runner/metrics/opentelemetry_metrics.ts +84 -0
  483. package/dist/scaffold-repo/triggers/http/src/runner/metrics/opentelemetry_traces.ts +30 -0
  484. package/dist/scaffold-repo/triggers/http/src/runner/nodeCatalog.ts +128 -0
  485. package/dist/scaffold-repo/triggers/http/src/runner/responseEmitter.ts +138 -0
  486. package/dist/scaffold-repo/triggers/http/src/runner/scanWorkflows.ts +201 -0
  487. package/dist/scaffold-repo/triggers/http/src/runner/types/ErrorResponse.ts +3 -0
  488. package/dist/scaffold-repo/triggers/http/src/runner/types/NodeTypes.ts +13 -0
  489. package/dist/scaffold-repo/triggers/http/src/runner/types/Nodes.ts +5 -0
  490. package/dist/scaffold-repo/triggers/http/src/runner/types/RuntimeWorkflow.ts +7 -0
  491. package/dist/scaffold-repo/triggers/http/src/runner/types/WorkflowRequest.ts +8 -0
  492. package/dist/scaffold-repo/triggers/http/src/runner/types/WorkflowResponse.ts +7 -0
  493. package/dist/scaffold-repo/triggers/http/src/runner/types/Workflows.ts +14 -0
  494. package/dist/scaffold-repo/triggers/http/src/workflows/countries-cats-helper.ts +30 -0
  495. package/dist/scaffold-repo/triggers/http/src/workflows/countries-handle-dsl.ts +25 -0
  496. package/dist/scaffold-repo/triggers/http/src/workflows/countries-helper.ts +18 -0
  497. package/dist/scaffold-repo/triggers/http/src/workflows/empty.ts +16 -0
  498. package/dist/scaffold-repo/triggers/http/src/workflows/eval/eval-retrieve.ts +23 -0
  499. package/dist/scaffold-repo/triggers/http/src/workflows/eval/eval-run.ts +39 -0
  500. package/dist/scaffold-repo/triggers/http/src/workflows/eval/foreign-auth.ts +24 -0
  501. package/dist/scaffold-repo/triggers/http/tsconfig.json +39 -0
  502. package/dist/scaffold-repo/triggers/http/vitest.config.ts +39 -0
  503. package/dist/scaffold-repo/triggers/http/workflows/json/agent-message.json +87 -0
  504. package/dist/scaffold-repo/triggers/http/workflows/json/agent-page.json +25 -0
  505. package/dist/scaffold-repo/triggers/http/workflows/json/agent-stream.json +30 -0
  506. package/dist/scaffold-repo/triggers/http/workflows/json/agent-tool-calculator.json +22 -0
  507. package/dist/scaffold-repo/triggers/http/workflows/json/agent-tool-weather.json +22 -0
  508. package/dist/scaffold-repo/triggers/http/workflows/json/chat-memory-message.json +54 -0
  509. package/dist/scaffold-repo/triggers/http/workflows/json/chat-memory-page.json +25 -0
  510. package/dist/scaffold-repo/triggers/http/workflows/json/chat-memory-stream.json +30 -0
  511. package/dist/scaffold-repo/triggers/http/workflows/json/chat-message.json +25 -0
  512. package/dist/scaffold-repo/triggers/http/workflows/json/chat-page.json +20 -0
  513. package/dist/scaffold-repo/triggers/http/workflows/json/chat-stream.json +30 -0
  514. package/dist/scaffold-repo/triggers/http/workflows/json/countries-py.json +27 -0
  515. package/dist/scaffold-repo/triggers/http/workflows/json/countries-vs-facts.json +50 -0
  516. package/dist/scaffold-repo/triggers/http/workflows/json/countries.json +27 -0
  517. package/dist/scaffold-repo/triggers/http/workflows/json/cross-runtime-chain.json +89 -0
  518. package/dist/scaffold-repo/triggers/http/workflows/json/dashboard-gen.json +34 -0
  519. package/dist/scaffold-repo/triggers/http/workflows/json/db-manager.json +34 -0
  520. package/dist/scaffold-repo/triggers/http/workflows/json/empty.json +13 -0
  521. package/dist/scaffold-repo/triggers/http/workflows/json/fanout-enqueue.json +48 -0
  522. package/dist/scaffold-repo/triggers/http/workflows/json/fanout-worker.json +41 -0
  523. package/dist/scaffold-repo/triggers/http/workflows/json/feedback.json +34 -0
  524. package/dist/scaffold-repo/triggers/http/workflows/json/films.json +27 -0
  525. package/dist/scaffold-repo/triggers/http/workflows/json/image-capture.json +34 -0
  526. package/dist/scaffold-repo/triggers/http/workflows/json/launches-by-year.json +27 -0
  527. package/dist/scaffold-repo/triggers/http/workflows/json/loadtest.json +24 -0
  528. package/dist/scaffold-repo/triggers/http/workflows/json/middleware/admin-only.json +31 -0
  529. package/dist/scaffold-repo/triggers/http/workflows/json/middleware/auth-check.json +59 -0
  530. package/dist/scaffold-repo/triggers/http/workflows/json/middleware/github-webhook-verify.json +34 -0
  531. package/dist/scaffold-repo/triggers/http/workflows/json/middleware/jwt-auth.json +46 -0
  532. package/dist/scaffold-repo/triggers/http/workflows/json/middleware/rate-limit.json +70 -0
  533. package/dist/scaffold-repo/triggers/http/workflows/json/middleware/redis-rate-limit.json +71 -0
  534. package/dist/scaffold-repo/triggers/http/workflows/json/mongodb.json +24 -0
  535. package/dist/scaffold-repo/triggers/http/workflows/json/rentals-pdf.json +65 -0
  536. package/dist/scaffold-repo/triggers/http/workflows/json/v05-admin-delete-user.json +42 -0
  537. package/dist/scaffold-repo/triggers/http/workflows/json/v05-async-job-poller.json +45 -0
  538. package/dist/scaffold-repo/triggers/http/workflows/json/v05-csv-import.json +122 -0
  539. package/dist/scaffold-repo/triggers/http/workflows/json/v05-data-export.json +105 -0
  540. package/dist/scaffold-repo/triggers/http/workflows/json/v05-event-router.json +97 -0
  541. package/dist/scaffold-repo/triggers/http/workflows/json/v05-github-handler-issues.json +22 -0
  542. package/dist/scaffold-repo/triggers/http/workflows/json/v05-github-handler-pr.json +22 -0
  543. package/dist/scaffold-repo/triggers/http/workflows/json/v05-github-handler-push.json +22 -0
  544. package/dist/scaffold-repo/triggers/http/workflows/json/v05-github-webhook-router.json +88 -0
  545. package/dist/scaffold-repo/triggers/http/workflows/json/v05-hello-global-mw.json +22 -0
  546. package/dist/scaffold-repo/triggers/http/workflows/json/v05-hello-with-mw.json +23 -0
  547. package/dist/scaffold-repo/triggers/http/workflows/json/v05-jwt-protected.json +23 -0
  548. package/dist/scaffold-repo/triggers/http/workflows/json/v05-multi-tenant-router.json +90 -0
  549. package/dist/scaffold-repo/triggers/http/workflows/json/v05-nested-control-flow.json +207 -0
  550. package/dist/scaffold-repo/triggers/http/workflows/json/v05-order-fulfillment.json +211 -0
  551. package/dist/scaffold-repo/triggers/http/workflows/json/v05-parallel-foreach-with-wait.json +47 -0
  552. package/dist/scaffold-repo/triggers/http/workflows/json/v05-polling-with-backoff.json +55 -0
  553. package/dist/scaffold-repo/triggers/http/workflows/json/v05-protected.json +23 -0
  554. package/dist/scaffold-repo/triggers/http/workflows/json/v05-redis-protected.json +23 -0
  555. package/dist/scaffold-repo/triggers/http/workflows/json/v05-saga.json +122 -0
  556. package/dist/scaffold-repo/triggers/http/workflows/json/v05-tenant-acme.json +22 -0
  557. package/dist/scaffold-repo/triggers/http/workflows/json/v05-tenant-beta.json +22 -0
  558. package/dist/scaffold-repo/triggers/http/workflows/json/v05-tenant-gamma.json +22 -0
  559. package/dist/scaffold-repo/triggers/http/workflows/json/v05-travel-booking.json +200 -0
  560. package/dist/scaffold-repo/triggers/http/workflows/json/v05-user-signup-saga.json +186 -0
  561. package/dist/scaffold-repo/triggers/http/workflows/json/v05-webhook-fanout.json +49 -0
  562. package/dist/scaffold-repo/triggers/http/workflows/json/v06-reliability-showcase.json +80 -0
  563. package/dist/scaffold-repo/triggers/http/workflows/json/v07-sse-publish.json +24 -0
  564. package/dist/scaffold-repo/triggers/http/workflows/json/v07-sse-stream.json +26 -0
  565. package/dist/scaffold-repo/triggers/http/workflows/json/v07-ws-echo.json +38 -0
  566. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-github-issues.json +22 -0
  567. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-github-pr.json +22 -0
  568. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-github-push.json +32 -0
  569. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-github.json +87 -0
  570. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-linear-comment.json +22 -0
  571. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-linear-issue.json +22 -0
  572. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-linear.json +74 -0
  573. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-stripe-customer-created.json +22 -0
  574. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-stripe-invoice-paid.json +32 -0
  575. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-stripe.json +24 -0
  576. package/dist/scaffold-repo/triggers/http/workflows/json/workflow-docs.json +34 -0
  577. package/dist/scaffold-repo/triggers/http/workflows/toml/countries.toml +21 -0
  578. package/dist/scaffold-repo/triggers/http/workflows/xml/countries.xml +23 -0
  579. package/dist/scaffold-repo/triggers/http/workflows/yaml/countries.yaml +19 -0
  580. package/dist/scaffold-repo/triggers/mcp/README.md +131 -0
  581. package/dist/scaffold-repo/triggers/mcp/package.json +39 -0
  582. package/dist/scaffold-repo/triggers/mcp/src/McpTrigger.ts +581 -0
  583. package/dist/scaffold-repo/triggers/mcp/src/index.ts +41 -0
  584. package/dist/scaffold-repo/triggers/mcp/tsconfig.json +32 -0
  585. package/dist/scaffold-repo/triggers/pubsub/CHANGELOG.md +22 -0
  586. package/dist/scaffold-repo/triggers/pubsub/package.json +66 -0
  587. package/dist/scaffold-repo/triggers/pubsub/src/PubSubTrigger.ts +424 -0
  588. package/dist/scaffold-repo/triggers/pubsub/src/adapters/AWSSNSAdapter.ts +352 -0
  589. package/dist/scaffold-repo/triggers/pubsub/src/adapters/AzureServiceBusAdapter.ts +303 -0
  590. package/dist/scaffold-repo/triggers/pubsub/src/adapters/GCPPubSubAdapter.ts +327 -0
  591. package/dist/scaffold-repo/triggers/pubsub/src/adapters/KafkaPubSubAdapter.ts +247 -0
  592. package/dist/scaffold-repo/triggers/pubsub/src/adapters/KafkaPubSubAdapter.ts.bak +251 -0
  593. package/dist/scaffold-repo/triggers/pubsub/src/adapters/NATSPubSubAdapter.ts +333 -0
  594. package/dist/scaffold-repo/triggers/pubsub/src/adapters/RedisStreamsPubSubAdapter.ts +256 -0
  595. package/dist/scaffold-repo/triggers/pubsub/src/adapters/factory.ts +88 -0
  596. package/dist/scaffold-repo/triggers/pubsub/src/index.ts +67 -0
  597. package/dist/scaffold-repo/triggers/pubsub/template/.env.example +8 -0
  598. package/dist/scaffold-repo/triggers/pubsub/template/package.json +45 -0
  599. package/dist/scaffold-repo/triggers/pubsub/template/src/Nodes.ts +20 -0
  600. package/dist/scaffold-repo/triggers/pubsub/template/src/Workflows.ts +8 -0
  601. package/dist/scaffold-repo/triggers/pubsub/template/src/index.ts +41 -0
  602. package/dist/scaffold-repo/triggers/pubsub/template/src/runner/PubSubServer.ts +39 -0
  603. package/dist/scaffold-repo/triggers/pubsub/template/src/runner/types/Workflows.ts +7 -0
  604. package/dist/scaffold-repo/triggers/pubsub/template/src/workflows/messages/on-message.ts +42 -0
  605. package/dist/scaffold-repo/triggers/pubsub/template/src/workflows/publish-order.ts +22 -0
  606. package/dist/scaffold-repo/triggers/pubsub/template/tsconfig.json +31 -0
  607. package/dist/scaffold-repo/triggers/pubsub/template/vitest.config.ts +39 -0
  608. package/dist/scaffold-repo/triggers/pubsub/tsconfig.json +32 -0
  609. package/dist/scaffold-repo/triggers/sse/.env.example +8 -0
  610. package/dist/scaffold-repo/triggers/sse/CHANGELOG.md +12 -0
  611. package/dist/scaffold-repo/triggers/sse/Dockerfile +47 -0
  612. package/dist/scaffold-repo/triggers/sse/Dockerfile.dev +33 -0
  613. package/dist/scaffold-repo/triggers/sse/package.json +37 -0
  614. package/dist/scaffold-repo/triggers/sse/src/SSETrigger.ts +489 -0
  615. package/dist/scaffold-repo/triggers/sse/src/bus.ts +208 -0
  616. package/dist/scaffold-repo/triggers/sse/src/index.ts +38 -0
  617. package/dist/scaffold-repo/triggers/sse/src/workflows/events/README.md +129 -0
  618. package/dist/scaffold-repo/triggers/sse/src/workflows/events/publish-demo.ts +40 -0
  619. package/dist/scaffold-repo/triggers/sse/src/workflows/events/stream-demo.ts +43 -0
  620. package/dist/scaffold-repo/triggers/sse/tsconfig.json +22 -0
  621. package/dist/scaffold-repo/triggers/sse/vitest.config.ts +39 -0
  622. package/dist/scaffold-repo/triggers/webhook/CHANGELOG.md +22 -0
  623. package/dist/scaffold-repo/triggers/webhook/package.json +36 -0
  624. package/dist/scaffold-repo/triggers/webhook/src/WebhookTrigger.ts +465 -0
  625. package/dist/scaffold-repo/triggers/webhook/src/index.ts +51 -0
  626. package/dist/scaffold-repo/triggers/webhook/src/verifiers.ts +394 -0
  627. package/dist/scaffold-repo/triggers/webhook/tsconfig.json +32 -0
  628. package/dist/scaffold-repo/triggers/websocket/.env.example +8 -0
  629. package/dist/scaffold-repo/triggers/websocket/CHANGELOG.md +22 -0
  630. package/dist/scaffold-repo/triggers/websocket/package.json +50 -0
  631. package/dist/scaffold-repo/triggers/websocket/src/Backplane.ts +167 -0
  632. package/dist/scaffold-repo/triggers/websocket/src/WebSocketTrigger.ts +910 -0
  633. package/dist/scaffold-repo/triggers/websocket/src/index.ts +50 -0
  634. package/dist/scaffold-repo/triggers/websocket/src/workflows/events/README.md +93 -0
  635. package/dist/scaffold-repo/triggers/websocket/src/workflows/events/echo-demo.ts +56 -0
  636. package/dist/scaffold-repo/triggers/websocket/tsconfig.json +22 -0
  637. package/dist/scaffold-repo/triggers/websocket/vitest.config.ts +39 -0
  638. package/dist/scaffold-repo/triggers/worker/CHANGELOG.md +22 -0
  639. package/dist/scaffold-repo/triggers/worker/package.json +68 -0
  640. package/dist/scaffold-repo/triggers/worker/src/WorkerTrigger.ts +943 -0
  641. package/dist/scaffold-repo/triggers/worker/src/adapters/BullMQAdapter.ts +296 -0
  642. package/dist/scaffold-repo/triggers/worker/src/adapters/InMemoryAdapter.ts +280 -0
  643. package/dist/scaffold-repo/triggers/worker/src/adapters/KafkaAdapter.ts +347 -0
  644. package/dist/scaffold-repo/triggers/worker/src/adapters/NATSAdapter.ts +505 -0
  645. package/dist/scaffold-repo/triggers/worker/src/adapters/PgBossAdapter.ts +319 -0
  646. package/dist/scaffold-repo/triggers/worker/src/adapters/RabbitMQAdapter.ts +318 -0
  647. package/dist/scaffold-repo/triggers/worker/src/adapters/RedisStreamsAdapter.ts +513 -0
  648. package/dist/scaffold-repo/triggers/worker/src/adapters/SQSAdapter.ts +314 -0
  649. package/dist/scaffold-repo/triggers/worker/src/adapters/factory.ts +111 -0
  650. package/dist/scaffold-repo/triggers/worker/src/index.ts +95 -0
  651. package/dist/scaffold-repo/triggers/worker/template/.env.example +18 -0
  652. package/dist/scaffold-repo/triggers/worker/template/package.json +46 -0
  653. package/dist/scaffold-repo/triggers/worker/template/src/Nodes.ts +20 -0
  654. package/dist/scaffold-repo/triggers/worker/template/src/Workflows.ts +8 -0
  655. package/dist/scaffold-repo/triggers/worker/template/src/index.ts +41 -0
  656. package/dist/scaffold-repo/triggers/worker/template/src/runner/WorkerServer.ts +34 -0
  657. package/dist/scaffold-repo/triggers/worker/template/src/runner/types/Workflows.ts +7 -0
  658. package/dist/scaffold-repo/triggers/worker/template/src/workflows/jobs/process-job.ts +40 -0
  659. package/dist/scaffold-repo/triggers/worker/template/tsconfig.json +31 -0
  660. package/dist/scaffold-repo/triggers/worker/template/vitest.config.ts +39 -0
  661. package/dist/scaffold-repo/triggers/worker/tsconfig.json +32 -0
  662. package/dist/scaffold-repo/workflows/json/agent-message.json +87 -0
  663. package/dist/scaffold-repo/workflows/json/agent-page.json +25 -0
  664. package/dist/scaffold-repo/workflows/json/agent-stream.json +30 -0
  665. package/dist/scaffold-repo/workflows/json/agent-tool-calculator.json +22 -0
  666. package/dist/scaffold-repo/workflows/json/agent-tool-weather.json +22 -0
  667. package/dist/scaffold-repo/workflows/json/chat-memory-message.json +54 -0
  668. package/dist/scaffold-repo/workflows/json/chat-memory-page.json +25 -0
  669. package/dist/scaffold-repo/workflows/json/chat-memory-stream.json +30 -0
  670. package/dist/scaffold-repo/workflows/json/chat-message.json +25 -0
  671. package/dist/scaffold-repo/workflows/json/chat-page.json +20 -0
  672. package/dist/scaffold-repo/workflows/json/chat-stream.json +30 -0
  673. package/dist/scaffold-repo/workflows/json/countries-vs-facts.json +50 -0
  674. package/dist/scaffold-repo/workflows/json/countries.json +27 -0
  675. package/dist/scaffold-repo/workflows/json/cron-heartbeat.json +15 -0
  676. package/dist/scaffold-repo/workflows/json/fanout-enqueue.json +48 -0
  677. package/dist/scaffold-repo/workflows/json/fanout-worker.json +41 -0
  678. package/dist/scaffold-repo/workflows/json/pubsub-on-order.json +24 -0
  679. package/dist/scaffold-repo/workflows/json/webhook-github-issues.json +22 -0
  680. package/dist/scaffold-repo/workflows/json/webhook-github-pr.json +22 -0
  681. package/dist/scaffold-repo/workflows/json/webhook-github-push.json +32 -0
  682. package/dist/scaffold-repo/workflows/json/webhook-github.json +87 -0
  683. package/dist/scaffold-repo/workflows/json/webhook-linear-comment.json +22 -0
  684. package/dist/scaffold-repo/workflows/json/webhook-linear-issue.json +22 -0
  685. package/dist/scaffold-repo/workflows/json/webhook-linear.json +74 -0
  686. package/dist/scaffold-repo/workflows/json/webhook-stripe-customer-created.json +22 -0
  687. package/dist/scaffold-repo/workflows/json/webhook-stripe-invoice-paid.json +32 -0
  688. package/dist/scaffold-repo/workflows/json/webhook-stripe.json +24 -0
  689. 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"]